From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY,URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 200F7C433E2 for ; Fri, 4 Sep 2020 13:27:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D213720722 for ; Fri, 4 Sep 2020 13:27:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="E4HakSBM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730354AbgIDN1b (ORCPT ); Fri, 4 Sep 2020 09:27:31 -0400 Received: from Mailgw01.mediatek.com ([1.203.163.78]:25044 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1730387AbgIDN1T (ORCPT ); Fri, 4 Sep 2020 09:27:19 -0400 X-UUID: cca63f7ac2b4419aa570b4c2ad939ff8-20200904 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=22/iNI1bCMO52DJ7zmxWRbPYhTPUczPRCXOpoQjmtnA=; b=E4HakSBMiE1GEukUex9ubr50exHxNd6BfJWTTLJemmHVaA4co8VDATqO90CopiSx4sCLKD8TWPaX4+iirCQr05jmyF7vimsQbq/gu4PwmxyI/4noYS4Mf0/08Ic6pfLY7Usdw9yTCXkwJZLZYdO85b8tMO3r1nPlroKPSkZb7NY=; X-UUID: cca63f7ac2b4419aa570b4c2ad939ff8-20200904 Received: from mtkcas32.mediatek.inc [(172.27.4.253)] by mailgw01.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 979048158; Fri, 04 Sep 2020 21:24:29 +0800 Received: from MTKCAS32.mediatek.inc (172.27.4.184) by MTKMBS31N2.mediatek.inc (172.27.4.87) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 4 Sep 2020 21:24:28 +0800 Received: from [10.17.3.153] (10.17.3.153) by MTKCAS32.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 4 Sep 2020 21:24:26 +0800 Message-ID: <1599225767.4733.64.camel@mhfsdcap03> Subject: Re: [PATCH v14 2/2] media: i2c: Add OV02A10 image sensor driver From: Dongchun Zhu To: Andy Shevchenko CC: , , , , , , , , , , , , , , , , , Date: Fri, 4 Sep 2020 21:22:47 +0800 In-Reply-To: <20200902134421.GN1891694@smile.fi.intel.com> References: <20200902120122.24456-1-dongchun.zhu@mediatek.com> <20200902120122.24456-3-dongchun.zhu@mediatek.com> <20200902134421.GN1891694@smile.fi.intel.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: 7677D1418206308CDF70BED27549441915906F398580126A8871507F2954C0E12000:8 X-MTK: N Content-Transfer-Encoding: base64 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org SGVsbG8gQW5keSwNCg0KVGhhbmtzIGZvciB0aGUgcmV2aWV3Lg0KDQpPbiBXZWQsIDIwMjAtMDkt MDIgYXQgMTY6NDQgKzAzMDAsIEFuZHkgU2hldmNoZW5rbyB3cm90ZToNCj4gT24gV2VkLCBTZXAg MDIsIDIwMjAgYXQgMDg6MDE6MjJQTSArMDgwMCwgRG9uZ2NodW4gWmh1IHdyb3RlOg0KPiA+IEFk ZCBhIFY0TDIgc3ViLWRldmljZSBkcml2ZXIgZm9yIE9tbmlWaXNpb24gT1YwMkExMCBpbWFnZSBz ZW5zb3IuDQo+ID4gDQo+IA0KPiBTb21lIG5pdC1waWNrcyBiZWxvdywgYWZ0ZXIgYWRkcmVzc2lu ZywgRldJVywNCj4gUmV2aWV3ZWQtYnk6IEFuZHkgU2hldmNoZW5rbyA8YW5kcml5LnNoZXZjaGVu a29AbGludXguaW50ZWwuY29tPg0KPiANCj4gPiBTaWduZWQtb2ZmLWJ5OiBEb25nY2h1biBaaHUg PGRvbmdjaHVuLnpodUBtZWRpYXRlay5jb20+DQo+ID4gLS0tDQo+ID4gIE1BSU5UQUlORVJTICAg ICAgICAgICAgICAgICB8ICAgIDEgKw0KPiA+ICBkcml2ZXJzL21lZGlhL2kyYy9LY29uZmlnICAg fCAgIDEzICsNCj4gPiAgZHJpdmVycy9tZWRpYS9pMmMvTWFrZWZpbGUgIHwgICAgMSArDQo+ID4g IGRyaXZlcnMvbWVkaWEvaTJjL292MDJhMTAuYyB8IDEwODMgKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICA0IGZpbGVzIGNoYW5nZWQsIDEwOTggaW5zZXJ0 aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9tZWRpYS9pMmMvb3YwMmEx MC5jDQo+ID4gDQo+ID4gZGlmZiAtLWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRBSU5FUlMNCj4g PiBpbmRleCA0OGFhN2E3Li5jZTdkOGZhIDEwMDY0NA0KPiA+IC0tLSBhL01BSU5UQUlORVJTDQo+ ID4gKysrIGIvTUFJTlRBSU5FUlMNCj4gPiBAQCAtMTI3MjQsNiArMTI3MjQsNyBAQCBMOglsaW51 eC1tZWRpYUB2Z2VyLmtlcm5lbC5vcmcNCj4gPiAgUzoJTWFpbnRhaW5lZA0KPiA+ICBUOglnaXQg Z2l0Oi8vbGludXh0di5vcmcvbWVkaWFfdHJlZS5naXQNCj4gPiAgRjoJRG9jdW1lbnRhdGlvbi9k ZXZpY2V0cmVlL2JpbmRpbmdzL21lZGlhL2kyYy9vdnRpLG92MDJhMTAueWFtbA0KPiA+ICtGOglk cml2ZXJzL21lZGlhL2kyYy9vdjAyYTEwLmMNCj4gPiAgDQo+ID4gIE9NTklWSVNJT04gT1YxMzg1 OCBTRU5TT1IgRFJJVkVSDQo+ID4gIE06CVNha2FyaSBBaWx1cyA8c2FrYXJpLmFpbHVzQGxpbnV4 LmludGVsLmNvbT4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tZWRpYS9pMmMvS2NvbmZpZyBi L2RyaXZlcnMvbWVkaWEvaTJjL0tjb25maWcNCj4gPiBpbmRleCA0OGFlNjBhLi5mNDU4ODA0IDEw MDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbWVkaWEvaTJjL0tjb25maWcNCj4gPiArKysgYi9kcml2 ZXJzL21lZGlhL2kyYy9LY29uZmlnDQo+ID4gQEAgLTgyNSw2ICs4MjUsMTkgQEAgY29uZmlnIFZJ REVPX0lNWDM1NQ0KPiA+ICAJICBUbyBjb21waWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBj aG9vc2UgTSBoZXJlOiB0aGUNCj4gPiAgCSAgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGlteDM1NS4N Cj4gPiAgDQo+ID4gK2NvbmZpZyBWSURFT19PVjAyQTEwDQo+ID4gKwl0cmlzdGF0ZSAiT21uaVZp c2lvbiBPVjAyQTEwIHNlbnNvciBzdXBwb3J0Ig0KPiANCj4gPiArCWRlcGVuZHMgb24gSTJDICYm IFZJREVPX1Y0TDINCj4gDQo+IER1bm5vIGlmIFY0TDIgbW9kdWxlcyBhbGxvdyBDT01QSUxFX1RF U1QsIGJ1dCBsb29raW5nIGJlbG93LCBjYW4gd2Ugc3RpY2sgd2l0aCBvbmUgcGF0dGVybiBsaWtl DQo+IAlkZXBlbmRzIG9uIFZJREVPX1Y0TDIgJiYgSTJDDQo+ID8NCj4gDQo+IE9yIGlzIGl0IHRo ZSBvcHBvc2l0ZSAoZGUgZmFjdG8gaW4gdXNlKT8NCj4gDQoNCkl0IHNlZW1zIHRoZXJlIGlzIG5v IHVuaWZvcm0gc3RhbmRhcmQgZm9yIHRoZSBkZXBlbmRlbmN5IHNlcXVlbmNlDQpjdXJyZW50bHku DQoNCj4gPiArCXNlbGVjdCBNRURJQV9DT05UUk9MTEVSDQo+ID4gKwlzZWxlY3QgVklERU9fVjRM Ml9TVUJERVZfQVBJDQo+ID4gKwlzZWxlY3QgVjRMMl9GV05PREUNCj4gPiArCWhlbHANCj4gPiAr CSAgVGhpcyBpcyBhIFZpZGVvNExpbnV4MiBzZW5zb3IgZHJpdmVyIGZvciB0aGUgT21uaVZpc2lv bg0KPiA+ICsJICBPVjAyQTEwIGNhbWVyYSBzZW5zb3IuDQo+ID4gKw0KPiA+ICsJICBUbyBjb21w aWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9vc2UgTSBoZXJlOiB0aGUNCj4gPiArCSAg bW9kdWxlIHdpbGwgYmUgY2FsbGVkIG92MDJhMTAuDQo+ID4gKw0KPiA+ICBjb25maWcgVklERU9f T1YyNjQwDQo+ID4gIAl0cmlzdGF0ZSAiT21uaVZpc2lvbiBPVjI2NDAgc2Vuc29yIHN1cHBvcnQi DQo+ID4gIAlkZXBlbmRzIG9uIFZJREVPX1Y0TDIgJiYgSTJDDQo+ID4gZGlmZiAtLWdpdCBhL2Ry aXZlcnMvbWVkaWEvaTJjL01ha2VmaWxlIGIvZHJpdmVycy9tZWRpYS9pMmMvTWFrZWZpbGUNCj4g PiBpbmRleCBmMGE3NzQ3Li5kYzI3ZTE0IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbWVkaWEv aTJjL01ha2VmaWxlDQo+ID4gKysrIGIvZHJpdmVycy9tZWRpYS9pMmMvTWFrZWZpbGUNCj4gPiBA QCAtNjQsNiArNjQsNyBAQCBvYmotJChDT05GSUdfVklERU9fVlAyN1NNUFgpICs9IHZwMjdzbXB4 Lm8NCj4gPiAgb2JqLSQoQ09ORklHX1ZJREVPX1NPTllfQlRGX01QWCkgKz0gc29ueS1idGYtbXB4 Lm8NCj4gPiAgb2JqLSQoQ09ORklHX1ZJREVPX1VQRDY0MDMxQSkgKz0gdXBkNjQwMzFhLm8NCj4g PiAgb2JqLSQoQ09ORklHX1ZJREVPX1VQRDY0MDgzKSArPSB1cGQ2NDA4My5vDQo+ID4gK29iai0k KENPTkZJR19WSURFT19PVjAyQTEwKSArPSBvdjAyYTEwLm8NCj4gPiAgb2JqLSQoQ09ORklHX1ZJ REVPX09WMjY0MCkgKz0gb3YyNjQwLm8NCj4gPiAgb2JqLSQoQ09ORklHX1ZJREVPX09WMjY4MCkg Kz0gb3YyNjgwLm8NCj4gPiAgb2JqLSQoQ09ORklHX1ZJREVPX09WMjY4NSkgKz0gb3YyNjg1Lm8N Cj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tZWRpYS9pMmMvb3YwMmExMC5jIGIvZHJpdmVycy9t ZWRpYS9pMmMvb3YwMmExMC5jDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAw MDAwMDAwLi4xZjhjNTI1DQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2RyaXZlcnMvbWVk aWEvaTJjL292MDJhMTAuYw0KPiA+IEBAIC0wLDAgKzEsMTA4MyBAQA0KPiA+ICsvLyBTUERYLUxp Y2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMA0KPiA+ICsvLyBDb3B5cmlnaHQgKGMpIDIwMjAgTWVk aWFUZWsgSW5jLg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPGxpbnV4L2Nsay5oPg0KPiA+ICsjaW5j bHVkZSA8bGludXgvZGVsYXkuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPg0KPiA+ ICsjaW5jbHVkZSA8bGludXgvZ3Bpby9jb25zdW1lci5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgv aTJjLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4NCj4gPiArI2luY2x1ZGUgPGxp bnV4L3BtX3J1bnRpbWUuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3JlZ3VsYXRvci9jb25zdW1l ci5oPg0KPiA+ICsjaW5jbHVkZSA8bWVkaWEvbWVkaWEtZW50aXR5Lmg+DQo+ID4gKyNpbmNsdWRl IDxtZWRpYS92NGwyLWFzeW5jLmg+DQo+ID4gKyNpbmNsdWRlIDxtZWRpYS92NGwyLWN0cmxzLmg+ DQo+ID4gKyNpbmNsdWRlIDxtZWRpYS92NGwyLXN1YmRldi5oPg0KPiA+ICsjaW5jbHVkZSA8bWVk aWEvdjRsMi1md25vZGUuaD4NCj4gPiArDQo+ID4gKyNkZWZpbmUgQ0hJUF9JRAkJCQkJCTB4MjUw OQ0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfUkVHX0NISVBfSURfSAkJCQkweDAyDQo+ID4gKyNkZWZp bmUgT1YwMkExMF9SRUdfQ0hJUF9JRF9MCQkJCTB4MDMNCj4gPiArDQo+ID4gKy8qIEJpdFsxXSB2 ZXJ0aWNhbCB1cHNpZGUgZG93biAqLw0KPiA+ICsvKiBCaXRbMF0gaG9yaXpvbnRhbCBtaXJyb3Ig Ki8NCj4gPiArI2RlZmluZSBSRUdfTUlSUk9SX0ZMSVBfQ09OVFJPTAkJCQkweDNmDQo+ID4gKw0K PiA+ICsvKiBPcmllbnRhdGlvbiAqLw0KPiA+ICsjZGVmaW5lIFJFR19NSVJST1JfRkxJUF9FTkFC TEUJCQkJMHgwMw0KPiA+ICsNCj4gPiArLyogQml0WzI6MF0gTUlQSSB0cmFuc21pc3Npb24gc3Bl ZWQgc2VsZWN0ICovDQo+ID4gKyNkZWZpbmUgVFhfU1BFRURfQVJFQV9TRUwJCQkJMHhhMQ0KPiA+ ICsjZGVmaW5lIE9WMDJBMTBfTUlQSV9UWF9TUEVFRF9ERUZBVUxUCQkJMHgwNA0KPiA+ICsNCj4g PiArI2RlZmluZSBSRUdfUEFHRV9TV0lUQ0gJCQkJCTB4ZmQNCj4gPiArI2RlZmluZSBSRUdfR0xP QkFMX0VGRkVDVElWRQkJCQkweDAxDQo+ID4gKyNkZWZpbmUgUkVHX0VOQUJMRQkJCQkJQklUKDAp DQo+ID4gKw0KPiA+ICsjZGVmaW5lIFJFR19TQ19DVFJMX01PREUJCQkJMHhhYw0KPiA+ICsjZGVm aW5lIFNDX0NUUkxfTU9ERV9TVEFOREJZCQkJCTB4MDANCj4gPiArI2RlZmluZSBTQ19DVFJMX01P REVfU1RSRUFNSU5HCQkJCTB4MDENCj4gPiArDQo+ID4gKyNkZWZpbmUgT1YwMkExMF9FWFBfU0hJ RlQJCQkJOA0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfUkVHX0VYUE9TVVJFX0gJCQkJMHgwMw0KPiA+ ICsjZGVmaW5lIE9WMDJBMTBfUkVHX0VYUE9TVVJFX0wJCQkJMHgwNA0KPiA+ICsjZGVmaW5lCU9W MDJBMTBfRVhQT1NVUkVfTUlOCQkJCTQNCj4gPiArI2RlZmluZSBPVjAyQTEwX0VYUE9TVVJFX01B WF9NQVJHSU4JCQk0DQo+ID4gKyNkZWZpbmUJT1YwMkExMF9FWFBPU1VSRV9TVEVQCQkJCTENCj4g PiArDQo+ID4gKyNkZWZpbmUgT1YwMkExMF9WVFNfU0hJRlQJCQkJOA0KPiA+ICsjZGVmaW5lIE9W MDJBMTBfUkVHX1ZUU19ICQkJCTB4MDUNCj4gPiArI2RlZmluZSBPVjAyQTEwX1JFR19WVFNfTAkJ CQkweDA2DQo+IA0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfVlRTX01BWAkJCQkJMHgyMDlmDQo+IA0K PiBIZXg/ICgxKQ0KPiANCj4gPiArI2RlZmluZSBPVjAyQTEwX0JBU0lDX0xJTkUJCQkJMTIyNA0K PiANCj4gRGVjaW1hbD8gKDIpDQo+IA0KPiA+ICsNCj4gPiArI2RlZmluZSBPVjAyQTEwX1JFR19H QUlOCQkJCTB4MjQNCj4gDQo+ID4gKyNkZWZpbmUgT1YwMkExMF9HQUlOX01JTgkJCQkweDEwDQo+ ID4gKyNkZWZpbmUgT1YwMkExMF9HQUlOX01BWAkJCQkweGY4DQo+ID4gKyNkZWZpbmUgT1YwMkEx MF9HQUlOX1NURVAJCQkJMHgwMQ0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfR0FJTl9ERUZBVUxUCQkJ CTB4NDANCj4gDQo+IE5vdCBzdXJlIHdoeSB0aGVzZSBhcmUgaW4gaGV4LCBidXQgb2theS4gUHJv YmFibHkgYSByZWFzb24gYmVoaW5kICgxKSBhbmQgKDIpDQo+IGFzIHdlbGwuDQo+IA0KDQpGcm9t IG15IHBlcnNwZWN0aXZlLCBPVjAyQTEwX0JBU0lDX0xJTkUgaXMgZGVmaW5lZCBmcm9tIHRoZSBh c3BlY3Qgb2YNCid1MzIgaGVpZ2h0JyBpbiAnc3RydWN0IG92MDJhMTBfbW9kZSc7IHdoaWxlIHRo ZSBvdGhlcnMgYXJlIHJlbGF0ZWQgd2l0aA0Kc2Vuc29yIHNwZWNpZmljIGNvbnRyb2wgcmVnaXN0 ZXJzLCBsaWtlIFZUUywgR0FJTiwgRVhQU09VUkUuLi4NCg0KPiA+ICsvKiBUZXN0IHBhdHRlcm4g Y29udHJvbCAqLw0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfUkVHX1RFU1RfUEFUVEVSTgkJCTB4YjYN Cj4gDQo+IEknbSB3b25kZXJpbmcgaWYgeW91IGNhbiByZWFycmFuZ2UgcmVnaXN0ZXJzIHRoYXQg dGhleSB3aWxsIGJlIHNvcnRlZCBieSB2YWx1ZS4NCj4gDQoNClRoZXkgYXJlIHN1cHBvc2VkIHRv IGJlIGNsYXNzaWZpZWQgYnkgY2F0ZWdvcnkuDQoNCj4gPiArI2RlZmluZSBIWl9QRVJfTUhaCQkJ CQkxMDAwMDAwTA0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfTElOS19GUkVRXzM5ME1IWgkJCSgzOTAg KiBIWl9QRVJfTUhaKQ0KPiA+ICsjZGVmaW5lIE9WMDJBMTBfRUNMS19GUkVRCQkJCSgyNCAqIEha X1BFUl9NSFopDQo+ID4gKyNkZWZpbmUgT1YwMkExMF9EQVRBX0xBTkVTCQkJCTENCj4gPiArI2Rl ZmluZSBPVjAyQTEwX0JJVFNfUEVSX1NBTVBMRQkJCQkxMA0KPiA+ICsNCj4gPiArc3RhdGljIGNv bnN0IGNoYXIgKiBjb25zdCBvdjAyYTEwX3N1cHBseV9uYW1lc1tdID0gew0KPiA+ICsJImRvdmRk IiwJLyogRGlnaXRhbCBJL08gcG93ZXIgKi8NCj4gPiArCSJhdmRkIiwJCS8qIEFuYWxvZyBwb3dl ciAqLw0KPiA+ICsJImR2ZGQiLAkJLyogRGlnaXRhbCBjb3JlIHBvd2VyICovDQo+ID4gK307DQo+ ID4gKw0KPiA+ICtzdHJ1Y3Qgb3YwMmExMF9yZWcgew0KPiA+ICsJdTggYWRkcjsNCj4gPiArCXU4 IHZhbDsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVjdCBvdjAyYTEwX3JlZ19saXN0IHsNCj4g PiArCXUzMiBudW1fb2ZfcmVnczsNCj4gPiArCWNvbnN0IHN0cnVjdCBvdjAyYTEwX3JlZyAqcmVn czsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVjdCBvdjAyYTEwX21vZGUgew0KPiA+ICsJdTMy IHdpZHRoOw0KPiA+ICsJdTMyIGhlaWdodDsNCj4gPiArCXUzMiBleHBfZGVmOw0KPiA+ICsJdTMy IGh0c19kZWY7DQo+ID4gKwl1MzIgdnRzX2RlZjsNCj4gPiArCWNvbnN0IHN0cnVjdCBvdjAyYTEw X3JlZ19saXN0IHJlZ19saXN0Ow0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IG92MDJhMTAg ew0KPiA+ICsJdTMyIGVjbGtfZnJlcTsNCj4gPiArCS8qIEluZGljYXRpb24gb2YgTUlQSSB0cmFu c21pc3Npb24gc3BlZWQgc2VsZWN0ICovDQo+ID4gKwl1MzIgbWlwaV9jbG9ja192b2x0YWdlOw0K PiA+ICsJLyogSW5kZXggb2YgbGluayBmcmVxdWVuY3kgY29uZmlnIHRvIGJlIHVzZWQgKi8NCj4g PiArCXUzMiBmcmVxX2luZGV4Ow0KPiA+ICsNCj4gPiArCXN0cnVjdCBjbGsgKmVjbGs7DQo+ID4g KwlzdHJ1Y3QgZ3Bpb19kZXNjICpwZF9ncGlvOw0KPiA+ICsJc3RydWN0IGdwaW9fZGVzYyAqcnN0 X2dwaW87DQo+ID4gKwlzdHJ1Y3QgcmVndWxhdG9yX2J1bGtfZGF0YSBzdXBwbGllc1tBUlJBWV9T SVpFKG92MDJhMTBfc3VwcGx5X25hbWVzKV07DQo+ID4gKw0KPiA+ICsJYm9vbCBzdHJlYW1pbmc7 DQo+ID4gKwlib29sIHVwc2lkZV9kb3duOw0KPiA+ICsNCj4gPiArCS8qDQo+ID4gKwkgKiBTZXJp YWxpemUgY29udHJvbCBhY2Nlc3MsIGdldC9zZXQgZm9ybWF0LCBnZXQgc2VsZWN0aW9uDQo+ID4g KwkgKiBhbmQgc3RhcnQgc3RyZWFtaW5nLg0KPiA+ICsJICovDQo+ID4gKwlzdHJ1Y3QgbXV0ZXgg bXV0ZXg7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9zdWJkZXYgc3ViZGV2Ow0KPiA+ICsJc3RydWN0IG1l ZGlhX3BhZCBwYWQ7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9tYnVzX2ZyYW1lZm10IGZtdDsNCj4gPiAr CXN0cnVjdCB2NGwyX2N0cmxfaGFuZGxlciBjdHJsX2hhbmRsZXI7DQo+ID4gKwlzdHJ1Y3QgdjRs Ml9jdHJsICpleHBvc3VyZTsNCj4gPiArDQo+ID4gKwljb25zdCBzdHJ1Y3Qgb3YwMmExMF9tb2Rl ICpjdXJfbW9kZTsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBpbmxpbmUgc3RydWN0IG92 MDJhMTAgKnRvX292MDJhMTAoc3RydWN0IHY0bDJfc3ViZGV2ICpzZCkNCj4gPiArew0KPiA+ICsJ cmV0dXJuIGNvbnRhaW5lcl9vZihzZCwgc3RydWN0IG92MDJhMTAsIHN1YmRldik7DQo+ID4gK30N Cj4gPiArDQo+ID4gKy8qDQo+ID4gKyAqIGVjbGsgMjRNaHoNCj4gPiArICogcGNsayAzOU1oeg0K PiA+ICsgKiBsaW5lbGVuZ3RoIDkzNCgweDNhNikNCj4gPiArICogZnJhbWVsZW5ndGggMTM5MCgw eDU2RSkNCj4gPiArICogZ3JhYndpbmRvd193aWR0aCAxNjAwDQo+ID4gKyAqIGdyYWJ3aW5kb3df aGVpZ2h0IDEyMDANCj4gPiArICogbWF4X2ZyYW1lcmF0ZSAzMGZwcw0KPiA+ICsgKiBtaXBpX2Rh dGFyYXRlIHBlciBsYW5lIDc4ME1icHMNCj4gPiArICovDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1 Y3Qgb3YwMmExMF9yZWcgb3YwMmExMF8xNjAweDEyMDBfcmVnc1tdID0gew0KPiA+ICsJezB4ZmQs IDB4MDF9LA0KPiA+ICsJezB4YWMsIDB4MDB9LA0KPiA+ICsJezB4ZmQsIDB4MDB9LA0KPiA+ICsJ ezB4MmYsIDB4Mjl9LA0KPiA+ICsJezB4MzQsIDB4MDB9LA0KPiA+ICsJezB4MzUsIDB4MjF9LA0K PiA+ICsJezB4MzAsIDB4MTV9LA0KPiA+ICsJezB4MzMsIDB4MDF9LA0KPiA+ICsJezB4ZmQsIDB4 MDF9LA0KPiA+ICsJezB4NDQsIDB4MDB9LA0KPiA+ICsJezB4MmEsIDB4NGN9LA0KPiA+ICsJezB4 MmIsIDB4MWV9LA0KPiA+ICsJezB4MmMsIDB4NjB9LA0KPiA+ICsJezB4MjUsIDB4MTF9LA0KPiA+ ICsJezB4MDMsIDB4MDF9LA0KPiA+ICsJezB4MDQsIDB4YWV9LA0KPiA+ICsJezB4MDksIDB4MDB9 LA0KPiA+ICsJezB4MGEsIDB4MDJ9LA0KPiA+ICsJezB4MDYsIDB4YTZ9LA0KPiA+ICsJezB4MzEs IDB4MDB9LA0KPiA+ICsJezB4MjQsIDB4NDB9LA0KPiA+ICsJezB4MDEsIDB4MDF9LA0KPiA+ICsJ ezB4ZmIsIDB4NzN9LA0KPiA+ICsJezB4ZmQsIDB4MDF9LA0KPiA+ICsJezB4MTYsIDB4MDR9LA0K PiA+ICsJezB4MWMsIDB4MDl9LA0KPiA+ICsJezB4MjEsIDB4NDJ9LA0KPiA+ICsJezB4MTIsIDB4 MDR9LA0KPiA+ICsJezB4MTMsIDB4MTB9LA0KPiA+ICsJezB4MTEsIDB4NDB9LA0KPiA+ICsJezB4 MzMsIDB4ODF9LA0KPiA+ICsJezB4ZDAsIDB4MDB9LA0KPiA+ICsJezB4ZDEsIDB4MDF9LA0KPiA+ ICsJezB4ZDIsIDB4MDB9LA0KPiA+ICsJezB4NTAsIDB4MTB9LA0KPiA+ICsJezB4NTEsIDB4MjN9 LA0KPiA+ICsJezB4NTIsIDB4MjB9LA0KPiA+ICsJezB4NTMsIDB4MTB9LA0KPiA+ICsJezB4NTQs IDB4MDJ9LA0KPiA+ICsJezB4NTUsIDB4MjB9LA0KPiA+ICsJezB4NTYsIDB4MDJ9LA0KPiA+ICsJ ezB4NTgsIDB4NDh9LA0KPiA+ICsJezB4NWQsIDB4MTV9LA0KPiA+ICsJezB4NWUsIDB4MDV9LA0K PiA+ICsJezB4NjYsIDB4NjZ9LA0KPiA+ICsJezB4NjgsIDB4Njh9LA0KPiA+ICsJezB4NmIsIDB4 MDB9LA0KPiA+ICsJezB4NmMsIDB4MDB9LA0KPiA+ICsJezB4NmYsIDB4NDB9LA0KPiA+ICsJezB4 NzAsIDB4NDB9LA0KPiA+ICsJezB4NzEsIDB4MGF9LA0KPiA+ICsJezB4NzIsIDB4ZjB9LA0KPiA+ ICsJezB4NzMsIDB4MTB9LA0KPiA+ICsJezB4NzUsIDB4ODB9LA0KPiA+ICsJezB4NzYsIDB4MTB9 LA0KPiA+ICsJezB4ODQsIDB4MDB9LA0KPiA+ICsJezB4ODUsIDB4MTB9LA0KPiA+ICsJezB4ODYs IDB4MTB9LA0KPiA+ICsJezB4ODcsIDB4MDB9LA0KPiA+ICsJezB4OGEsIDB4MjJ9LA0KPiA+ICsJ ezB4OGIsIDB4MjJ9LA0KPiA+ICsJezB4MTksIDB4ZjF9LA0KPiA+ICsJezB4MjksIDB4MDF9LA0K PiA+ICsJezB4ZmQsIDB4MDF9LA0KPiA+ICsJezB4OWQsIDB4MTZ9LA0KPiA+ICsJezB4YTAsIDB4 Mjl9LA0KPiA+ICsJezB4YTEsIDB4MDR9LA0KPiA+ICsJezB4YWQsIDB4NjJ9LA0KPiA+ICsJezB4 YWUsIDB4MDB9LA0KPiA+ICsJezB4YWYsIDB4ODV9LA0KPiA+ICsJezB4YjEsIDB4MDF9LA0KPiA+ ICsJezB4OGUsIDB4MDZ9LA0KPiA+ICsJezB4OGYsIDB4NDB9LA0KPiA+ICsJezB4OTAsIDB4MDR9 LA0KPiA+ICsJezB4OTEsIDB4YjB9LA0KPiA+ICsJezB4NDUsIDB4MDF9LA0KPiA+ICsJezB4NDYs IDB4MDB9LA0KPiA+ICsJezB4NDcsIDB4NmN9LA0KPiA+ICsJezB4NDgsIDB4MDN9LA0KPiA+ICsJ ezB4NDksIDB4OGJ9LA0KPiA+ICsJezB4NGEsIDB4MDB9LA0KPiA+ICsJezB4NGIsIDB4MDd9LA0K PiA+ICsJezB4NGMsIDB4MDR9LA0KPiA+ICsJezB4NGQsIDB4Yjd9LA0KPiA+ICsJezB4ZjAsIDB4 NDB9LA0KPiA+ICsJezB4ZjEsIDB4NDB9LA0KPiA+ICsJezB4ZjIsIDB4NDB9LA0KPiA+ICsJezB4 ZjMsIDB4NDB9LA0KPiA+ICsJezB4M2YsIDB4MDB9LA0KPiA+ICsJezB4ZmQsIDB4MDF9LA0KPiA+ ICsJezB4MDUsIDB4MDB9LA0KPiA+ICsJezB4MDYsIDB4YTZ9LA0KPiA+ICsJezB4ZmQsIDB4MDF9 LA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IGNoYXIgKiBjb25zdCBvdjAyYTEw X3Rlc3RfcGF0dGVybl9tZW51W10gPSB7DQo+ID4gKwkiRGlzYWJsZWQiLA0KPiA+ICsJIkVpZ2h0 IFZlcnRpY2FsIENvbG91ciBCYXJzIiwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25z dCBzNjQgbGlua19mcmVxX21lbnVfaXRlbXNbXSA9IHsNCj4gPiArCU9WMDJBMTBfTElOS19GUkVR XzM5ME1IWiwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyB1NjQgdG9fcGl4ZWxfcmF0ZSh1 MzIgZl9pbmRleCkNCj4gPiArew0KPiA+ICsJdTY0IHBpeGVsX3JhdGUgPSBsaW5rX2ZyZXFfbWVu dV9pdGVtc1tmX2luZGV4XSAqIDIgKiBPVjAyQTEwX0RBVEFfTEFORVM7DQo+ID4gKw0KPiA+ICsJ ZG9fZGl2KHBpeGVsX3JhdGUsIE9WMDJBMTBfQklUU19QRVJfU0FNUExFKTsNCj4gPiArDQo+ID4g KwlyZXR1cm4gcGl4ZWxfcmF0ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0 cnVjdCBvdjAyYTEwX21vZGUgc3VwcG9ydGVkX21vZGVzW10gPSB7DQo+ID4gKwl7DQo+ID4gKwkJ LndpZHRoID0gMTYwMCwNCj4gPiArCQkuaGVpZ2h0ID0gMTIwMCwNCj4gPiArCQkuZXhwX2RlZiA9 IDB4MDFhZSwNCj4gPiArCQkuaHRzX2RlZiA9IDB4MDNhNiwNCj4gPiArCQkudnRzX2RlZiA9IDB4 MDU2ZSwNCj4gPiArCQkucmVnX2xpc3QgPSB7DQo+ID4gKwkJCS5udW1fb2ZfcmVncyA9IEFSUkFZ X1NJWkUob3YwMmExMF8xNjAweDEyMDBfcmVncyksDQo+ID4gKwkJCS5yZWdzID0gb3YwMmExMF8x NjAweDEyMDBfcmVncywNCj4gPiArCQl9LA0KPiA+ICsJfSwNCj4gPiArfTsNCj4gPiArDQo+ID4g K3N0YXRpYyBpbnQgb3YwMmExMF93cml0ZV9hcnJheShzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCwN Cj4gPiArCQkJICAgICAgIGNvbnN0IHN0cnVjdCBvdjAyYTEwX3JlZ19saXN0ICpyX2xpc3QpDQo+ ID4gK3sNCj4gPiArCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSB2NGwyX2dldF9zdWJkZXZk YXRhKCZvdjAyYTEwLT5zdWJkZXYpOw0KPiA+ICsJdW5zaWduZWQgaW50IGk7DQo+ID4gKwlpbnQg cmV0Ow0KPiA+ICsNCj4gPiArCWZvciAoaSA9IDA7IGkgPCByX2xpc3QtPm51bV9vZl9yZWdzOyBp KyspIHsNCj4gPiArCQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgcl9s aXN0LT5yZWdzW2ldLmFkZHIsDQo+ID4gKwkJCQkJCXJfbGlzdC0+cmVnc1tpXS52YWwpOw0KPiA+ ICsJCWlmIChyZXQgPCAwKQ0KPiA+ICsJCQlyZXR1cm4gcmV0Ow0KPiA+ICsJfQ0KPiA+ICsNCj4g PiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IG92MDJhMTBfcmVh ZF9zbWJ1cyhzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCwgdW5zaWduZWQgY2hhciByZWcsDQo+ID4g KwkJCSAgICAgIHVuc2lnbmVkIGNoYXIgKnZhbCkNCj4gPiArew0KPiA+ICsJc3RydWN0IGkyY19j bGllbnQgKmNsaWVudCA9IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92MDJhMTAtPnN1YmRldik7DQo+ ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCXJldCA9IGkyY19zbWJ1c19yZWFkX2J5dGVfZGF0 YShjbGllbnQsIHJlZyk7DQo+ID4gKwlpZiAocmV0IDwgMCkNCj4gPiArCQlyZXR1cm4gcmV0Ow0K PiA+ICsNCj4gPiArCSp2YWwgPSAodW5zaWduZWQgY2hhcilyZXQ7DQo+IA0KPiBObyBzdXJlIHdo eSB5b3UgaGF2ZSBjYXN0aW5nIGFuZCB3aHkgcmV0dXJuZWQgdmFsdWUgaXMgbm90IHU4Lg0KPiAN Cg0KRmluZS4gJ3Vuc2lnbmVkIGNoYXInIHdvdWxkIGJlIHJlcGxhY2VkIG9mICd1OCcgaW4gbmV4 dCByZWxlYXNlLg0KDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGlj IHZvaWQgb3YwMmExMF9maWxsX2ZtdChjb25zdCBzdHJ1Y3Qgb3YwMmExMF9tb2RlICptb2RlLA0K PiA+ICsJCQkgICAgIHN0cnVjdCB2NGwyX21idXNfZnJhbWVmbXQgKmZtdCkNCj4gPiArew0KPiA+ ICsJZm10LT53aWR0aCA9IG1vZGUtPndpZHRoOw0KPiA+ICsJZm10LT5oZWlnaHQgPSBtb2RlLT5o ZWlnaHQ7DQo+ID4gKwlmbXQtPmZpZWxkID0gVjRMMl9GSUVMRF9OT05FOw0KPiA+ICt9DQo+ID4g Kw0KPiA+ICtzdGF0aWMgaW50IG92MDJhMTBfc2V0X2ZtdChzdHJ1Y3QgdjRsMl9zdWJkZXYgKnNk LA0KPiA+ICsJCQkgICBzdHJ1Y3QgdjRsMl9zdWJkZXZfcGFkX2NvbmZpZyAqY2ZnLA0KPiA+ICsJ CQkgICBzdHJ1Y3QgdjRsMl9zdWJkZXZfZm9ybWF0ICpmbXQpDQo+ID4gK3sNCj4gPiArCXN0cnVj dCBvdjAyYTEwICpvdjAyYTEwID0gdG9fb3YwMmExMChzZCk7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9t YnVzX2ZyYW1lZm10ICptYnVzX2ZtdCA9ICZmbXQtPmZvcm1hdDsNCj4gPiArCXN0cnVjdCB2NGwy X21idXNfZnJhbWVmbXQgKmZyYW1lX2ZtdDsNCj4gPiArCWludCByZXQgPSAwOw0KPiA+ICsNCj4g PiArCW11dGV4X2xvY2soJm92MDJhMTAtPm11dGV4KTsNCj4gPiArDQo+ID4gKwlpZiAob3YwMmEx MC0+c3RyZWFtaW5nICYmIGZtdC0+d2hpY2ggPT0gVjRMMl9TVUJERVZfRk9STUFUX0FDVElWRSkg ew0KPiA+ICsJCXJldCA9IC1FQlVTWTsNCj4gPiArCQlnb3RvIGVycm9yOw0KPiA+ICsJfQ0KPiA+ ICsNCj4gPiArCS8qIE9ubHkgb25lIHNlbnNvciBtb2RlIHN1cHBvcnRlZCAqLw0KPiA+ICsJbWJ1 c19mbXQtPmNvZGUgPSBvdjAyYTEwLT5mbXQuY29kZTsNCj4gPiArCW92MDJhMTBfZmlsbF9mbXQo b3YwMmExMC0+Y3VyX21vZGUsIG1idXNfZm10KTsNCj4gPiArDQo+ID4gKwlpZiAoZm10LT53aGlj aCA9PSBWNEwyX1NVQkRFVl9GT1JNQVRfVFJZKQ0KPiA+ICsJCWZyYW1lX2ZtdCA9IHY0bDJfc3Vi ZGV2X2dldF90cnlfZm9ybWF0KHNkLCBjZmcsIDApOw0KPiA+ICsJZWxzZQ0KPiA+ICsJCWZyYW1l X2ZtdCA9ICZvdjAyYTEwLT5mbXQ7DQo+ID4gKw0KPiA+ICsJKmZyYW1lX2ZtdCA9ICptYnVzX2Zt dDsNCj4gPiArDQo+ID4gK2Vycm9yOg0KPiANCj4gTGlrZSBpbiBvdGhlciBwbGFjZXMgYmUgbW9y ZSBwcmVjaXNlDQo+IA0KPiBvdXRfdW5sb2NrOg0KPiANCg0KU291bmRzIGdvb2QgbmFtaW5nLg0K Rml4ZWQgaW4gbmV4dCByZWxlYXNlLg0KDQo+ID4gKwltdXRleF91bmxvY2soJm92MDJhMTAtPm11 dGV4KTsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQg b3YwMmExMF9nZXRfZm10KHN0cnVjdCB2NGwyX3N1YmRldiAqc2QsDQo+ID4gKwkJCSAgIHN0cnVj dCB2NGwyX3N1YmRldl9wYWRfY29uZmlnICpjZmcsDQo+ID4gKwkJCSAgIHN0cnVjdCB2NGwyX3N1 YmRldl9mb3JtYXQgKmZtdCkNCj4gPiArew0KPiA+ICsJc3RydWN0IG92MDJhMTAgKm92MDJhMTAg PSB0b19vdjAyYTEwKHNkKTsNCj4gPiArCXN0cnVjdCB2NGwyX21idXNfZnJhbWVmbXQgKm1idXNf Zm10ID0gJmZtdC0+Zm9ybWF0Ow0KPiA+ICsNCj4gPiArCW11dGV4X2xvY2soJm92MDJhMTAtPm11 dGV4KTsNCj4gPiArDQo+ID4gKwlpZiAoZm10LT53aGljaCA9PSBWNEwyX1NVQkRFVl9GT1JNQVRf VFJZKSB7DQo+ID4gKwkJZm10LT5mb3JtYXQgPSAqdjRsMl9zdWJkZXZfZ2V0X3RyeV9mb3JtYXQo c2QsIGNmZywgZm10LT5wYWQpOw0KPiA+ICsJfSBlbHNlIHsNCj4gPiArCQlmbXQtPmZvcm1hdCA9 IG92MDJhMTAtPmZtdDsNCj4gPiArCQltYnVzX2ZtdC0+Y29kZSA9IG92MDJhMTAtPmZtdC5jb2Rl Ow0KPiA+ICsJCW92MDJhMTBfZmlsbF9mbXQob3YwMmExMC0+Y3VyX21vZGUsIG1idXNfZm10KTsN Cj4gPiArCX0NCj4gPiArDQo+ID4gKwltdXRleF91bmxvY2soJm92MDJhMTAtPm11dGV4KTsNCj4g PiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBvdjAy YTEwX2VudW1fbWJ1c19jb2RlKHN0cnVjdCB2NGwyX3N1YmRldiAqc2QsDQo+ID4gKwkJCQkgIHN0 cnVjdCB2NGwyX3N1YmRldl9wYWRfY29uZmlnICpjZmcsDQo+ID4gKwkJCQkgIHN0cnVjdCB2NGwy X3N1YmRldl9tYnVzX2NvZGVfZW51bSAqY29kZSkNCj4gPiArew0KPiA+ICsJc3RydWN0IG92MDJh MTAgKm92MDJhMTAgPSB0b19vdjAyYTEwKHNkKTsNCj4gPiArDQo+ID4gKwlpZiAoY29kZS0+aW5k ZXggIT0gMCkNCj4gPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gPiArDQo+ID4gKwljb2RlLT5jb2Rl ID0gb3YwMmExMC0+Zm10LmNvZGU7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4g PiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9lbnVtX2ZyYW1lX3NpemVzKHN0cnVjdCB2NGwy X3N1YmRldiAqc2QsDQo+ID4gKwkJCQkgICAgc3RydWN0IHY0bDJfc3ViZGV2X3BhZF9jb25maWcg KmNmZywNCj4gPiArCQkJCSAgICBzdHJ1Y3QgdjRsMl9zdWJkZXZfZnJhbWVfc2l6ZV9lbnVtICpm c2UpDQo+ID4gK3sNCj4gPiArCWlmIChmc2UtPmluZGV4ID49IEFSUkFZX1NJWkUoc3VwcG9ydGVk X21vZGVzKSkNCj4gPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gPiArDQo+ID4gKwlmc2UtPm1pbl93 aWR0aCAgPSBzdXBwb3J0ZWRfbW9kZXNbZnNlLT5pbmRleF0ud2lkdGg7DQo+ID4gKwlmc2UtPm1h eF93aWR0aCAgPSBzdXBwb3J0ZWRfbW9kZXNbZnNlLT5pbmRleF0ud2lkdGg7DQo+ID4gKwlmc2Ut Pm1heF9oZWlnaHQgPSBzdXBwb3J0ZWRfbW9kZXNbZnNlLT5pbmRleF0uaGVpZ2h0Ow0KPiA+ICsJ ZnNlLT5taW5faGVpZ2h0ID0gc3VwcG9ydGVkX21vZGVzW2ZzZS0+aW5kZXhdLmhlaWdodDsNCj4g PiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBvdjAy YTEwX2NoZWNrX3NlbnNvcl9pZChzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCkNCj4gPiArew0KPiA+ ICsJc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92MDJh MTAtPnN1YmRldik7DQo+ID4gKwl1MTYgaWQ7DQo+ID4gKwl1OCBjaGlwX2lkX2g7DQo+ID4gKwl1 OCBjaGlwX2lkX2w7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCS8qIENoZWNrIHNlbnNv ciByZXZpc2lvbiAqLw0KPiA+ICsJcmV0ID0gb3YwMmExMF9yZWFkX3NtYnVzKG92MDJhMTAsIE9W MDJBMTBfUkVHX0NISVBfSURfSCwgJmNoaXBfaWRfaCk7DQo+ID4gKwlpZiAocmV0KQ0KPiA+ICsJ CXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJcmV0ID0gb3YwMmExMF9yZWFkX3NtYnVzKG92MDJh MTAsIE9WMDJBMTBfUkVHX0NISVBfSURfTCwgJmNoaXBfaWRfbCk7DQo+ID4gKwlpZiAocmV0KQ0K PiA+ICsJCXJldHVybiByZXQ7DQo+IA0KPiBJJ20gd29uZGVyaW5nIGlmIGFib3ZlIGNhbiBiZSBk b25lIGluIG9uZSBidWxrIHRyYW5zZmVyIChyZWFkaW5nIDE2LWJpdCB2YWx1ZSkuDQo+IA0KPiA+ ICsJaWQgPSAoY2hpcF9pZF9oIDw8IDgpIHwgY2hpcF9pZF9sOw0KPiANCj4gSWYgYWJvdmUgY2Fu IGJlIGFjaGlldmVkLCB0aGlzIG9uZSBzaG91bGQgYmUgcmF0aGVyIHNvbWV0aGluZyBsaWtlDQo+ IGxlMTZfdG9fY3B1KCkgKG9yIGJlMTYpIHdpdGggY29ycmVzcG9uZGluZyB0eXBlIG9mIGNoaXBf aWQuDQo+IA0KDQpZZXMuIGkyY19zbWJ1c19yZWFkX3dvcmRfZGF0YSgpIGZ1bmN0aW9ucyBjb3Vs ZCByZWFkIGJvdGggcmVnaXN0ZXJzIGluDQp1c2luZyBhIHNpbmdsZSBpMmMgdHJhbnNhY3Rpb24u DQpMZXQgbWUgdHJ5IGxvY2FsbHkgZmlyc3QuDQoNCj4gPiArCWlmIChpZCAhPSBDSElQX0lEKSB7 DQo+ID4gKwkJZGV2X2VycigmY2xpZW50LT5kZXYsICJVbmV4cGVjdGVkIHNlbnNvciBpZCglMDR4 KVxuIiwgaWQpOw0KPiA+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiAr CXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IG92MDJhMTBfcG93ZXJf b24oc3RydWN0IGRldmljZSAqZGV2KQ0KPiA+ICt7DQo+IA0KPiA+ICsJc3RydWN0IGkyY19jbGll bnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQoZGV2KTsNCj4gPiArCXN0cnVjdCB2NGwyX3N1YmRl diAqc2QgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsNCj4gDQo+IAlzdHJ1Y3QgdjRsMl9z dWJkZXYgKnNkID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+IA0KPiBTYW1lIGZvciB0aGUgcmVz dCBzaW1pbGFyIGNhc2VzLg0KPiANCg0KV2UndmUgZGlzY3Vzc2VkIHRoZSBpc3N1ZSBpbiBEVzk3 NjggVjIuDQoNCkZvciBWNEwyIHN1Yi1kZXZpY2UgZHJpdmVycywgZGV2X2dldF9kcnZkYXRhKCkg c2hvdWxkbid0IGJlIHVzZWQNCmRpcmVjdGx5Lg0KDQpNb3JlIGRldGFpbHMgcGxlYXNlIGNoZWNr IHRoZSBHb29nbGUgSXNzdWU6DQpodHRwczovL3BhcnRuZXJpc3N1ZXRyYWNrZXIuY29ycC5nb29n bGUuY29tL2lzc3Vlcy8xNDc5NTc5NzUNCg0KDQo+ID4gKwlzdHJ1Y3Qgb3YwMmExMCAqb3YwMmEx MCA9IHRvX292MDJhMTAoc2QpOw0KPiA+ICsJaW50IHJldDsNCj4gPiArDQo+ID4gKwlncGlvZF9z ZXRfdmFsdWVfY2Fuc2xlZXAob3YwMmExMC0+cnN0X2dwaW8sIDEpOw0KPiA+ICsJZ3Bpb2Rfc2V0 X3ZhbHVlX2NhbnNsZWVwKG92MDJhMTAtPnBkX2dwaW8sIDEpOw0KPiA+ICsNCj4gPiArCXJldCA9 IGNsa19wcmVwYXJlX2VuYWJsZShvdjAyYTEwLT5lY2xrKTsNCj4gPiArCWlmIChyZXQgPCAwKSB7 DQo+ID4gKwkJZGV2X2VycihkZXYsICJmYWlsZWQgdG8gZW5hYmxlIGVjbGtcbiIpOw0KPiA+ICsJ CXJldHVybiByZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0ID0gcmVndWxhdG9yX2J1bGtf ZW5hYmxlKEFSUkFZX1NJWkUob3YwMmExMF9zdXBwbHlfbmFtZXMpLA0KPiA+ICsJCQkJICAgIG92 MDJhMTAtPnN1cHBsaWVzKTsNCj4gPiArCWlmIChyZXQgPCAwKSB7DQo+ID4gKwkJZGV2X2Vycihk ZXYsICJmYWlsZWQgdG8gZW5hYmxlIHJlZ3VsYXRvcnNcbiIpOw0KPiA+ICsJCWdvdG8gZGlzYWJs ZV9jbGs7DQo+ID4gKwl9DQo+ID4gKwl1c2xlZXBfcmFuZ2UoNTAwMCwgNjAwMCk7DQo+ID4gKw0K PiA+ICsJZ3Bpb2Rfc2V0X3ZhbHVlX2NhbnNsZWVwKG92MDJhMTAtPnBkX2dwaW8sIDApOw0KPiA+ ICsJdXNsZWVwX3JhbmdlKDUwMDAsIDYwMDApOw0KPiA+ICsNCj4gPiArCWdwaW9kX3NldF92YWx1 ZV9jYW5zbGVlcChvdjAyYTEwLT5yc3RfZ3BpbywgMCk7DQo+ID4gKwl1c2xlZXBfcmFuZ2UoNTAw MCwgNjAwMCk7DQo+ID4gKw0KPiA+ICsJcmV0ID0gb3YwMmExMF9jaGVja19zZW5zb3JfaWQob3Yw MmExMCk7DQo+ID4gKwlpZiAocmV0KQ0KPiA+ICsJCWdvdG8gZGlzYWJsZV9yZWd1bGF0b3I7DQo+ ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICtkaXNhYmxlX3JlZ3VsYXRvcjoNCj4g PiArCXJlZ3VsYXRvcl9idWxrX2Rpc2FibGUoQVJSQVlfU0laRShvdjAyYTEwX3N1cHBseV9uYW1l cyksDQo+ID4gKwkJCSAgICAgICBvdjAyYTEwLT5zdXBwbGllcyk7DQo+ID4gK2Rpc2FibGVfY2xr Og0KPiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKG92MDJhMTAtPmVjbGspOw0KPiA+ICsNCj4g PiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9w b3dlcl9vZmYoc3RydWN0IGRldmljZSAqZGV2KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgaTJjX2Ns aWVudCAqY2xpZW50ID0gdG9faTJjX2NsaWVudChkZXYpOw0KPiA+ICsJc3RydWN0IHY0bDJfc3Vi ZGV2ICpzZCA9IGkyY19nZXRfY2xpZW50ZGF0YShjbGllbnQpOw0KPiA+ICsJc3RydWN0IG92MDJh MTAgKm92MDJhMTAgPSB0b19vdjAyYTEwKHNkKTsNCj4gPiArDQo+ID4gKwlncGlvZF9zZXRfdmFs dWVfY2Fuc2xlZXAob3YwMmExMC0+cnN0X2dwaW8sIDEpOw0KPiA+ICsJY2xrX2Rpc2FibGVfdW5w cmVwYXJlKG92MDJhMTAtPmVjbGspOw0KPiA+ICsJZ3Bpb2Rfc2V0X3ZhbHVlX2NhbnNsZWVwKG92 MDJhMTAtPnBkX2dwaW8sIDEpOw0KPiA+ICsJcmVndWxhdG9yX2J1bGtfZGlzYWJsZShBUlJBWV9T SVpFKG92MDJhMTBfc3VwcGx5X25hbWVzKSwNCj4gPiArCQkJICAgICAgIG92MDJhMTAtPnN1cHBs aWVzKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGlj IGludCBfX292MDJhMTBfc3RhcnRfc3RyZWFtKHN0cnVjdCBvdjAyYTEwICpvdjAyYTEwKQ0KPiA+ ICt7DQo+ID4gKwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50ID0gdjRsMl9nZXRfc3ViZGV2ZGF0 YSgmb3YwMmExMC0+c3ViZGV2KTsNCj4gPiArCWNvbnN0IHN0cnVjdCBvdjAyYTEwX3JlZ19saXN0 ICpyZWdfbGlzdDsNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJLyogQXBwbHkgZGVmYXVs dCB2YWx1ZXMgb2YgY3VycmVudCBtb2RlICovDQo+ID4gKwlyZWdfbGlzdCA9ICZvdjAyYTEwLT5j dXJfbW9kZS0+cmVnX2xpc3Q7DQo+ID4gKwlyZXQgPSBvdjAyYTEwX3dyaXRlX2FycmF5KG92MDJh MTAsIHJlZ19saXN0KTsNCj4gPiArCWlmIChyZXQpDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiAr DQo+ID4gKwkvKiBBcHBseSBjdXN0b21pemVkIHZhbHVlcyBmcm9tIHVzZXIgKi8NCj4gPiArCXJl dCA9IF9fdjRsMl9jdHJsX2hhbmRsZXJfc2V0dXAob3YwMmExMC0+c3ViZGV2LmN0cmxfaGFuZGxl cik7DQo+ID4gKwlpZiAocmV0KQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJLyog U2V0IG9yaWVudGF0aW9uIHRvIDE4MCBkZWdyZWUgKi8NCj4gPiArCWlmIChvdjAyYTEwLT51cHNp ZGVfZG93bikgew0KPiA+ICsJCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50 LCBSRUdfTUlSUk9SX0ZMSVBfQ09OVFJPTCwNCj4gPiArCQkJCQkJUkVHX01JUlJPUl9GTElQX0VO QUJMRSk7DQo+ID4gKwkJaWYgKHJldCkgew0KPiA+ICsJCQlkZXZfZXJyKCZjbGllbnQtPmRldiwg ImZhaWxlZCB0byBzZXQgb3JpZW50YXRpb25cbiIpOw0KPiA+ICsJCQlyZXR1cm4gcmV0Ow0KPiA+ ICsJCX0NCj4gPiArCQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgUkVH X0dMT0JBTF9FRkZFQ1RJVkUsDQo+ID4gKwkJCQkJCVJFR19FTkFCTEUpOw0KPiA+ICsJCWlmIChy ZXQgPCAwKQ0KPiA+ICsJCQlyZXR1cm4gcmV0Ow0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCS8qIFNl dCBNSVBJIFRYIHNwZWVkIGFjY29yZGluZyB0byBEVCBwcm9wZXJ0eSAqLw0KPiA+ICsJaWYgKG92 MDJhMTAtPm1pcGlfY2xvY2tfdm9sdGFnZSAhPSBPVjAyQTEwX01JUElfVFhfU1BFRURfREVGQVVM VCkgew0KPiA+ICsJCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBUWF9T UEVFRF9BUkVBX1NFTCwNCj4gPiArCQkJCQkJb3YwMmExMC0+bWlwaV9jbG9ja192b2x0YWdlKTsN Cj4gPiArCQlpZiAocmV0IDwgMCkNCj4gPiArCQkJcmV0dXJuIHJldDsNCj4gPiArCX0NCj4gPiAr DQo+ID4gKwkvKiBTZXQgc3RyZWFtIG9uIHJlZ2lzdGVyICovDQo+ID4gKwlyZXR1cm4gaTJjX3Nt YnVzX3dyaXRlX2J5dGVfZGF0YShjbGllbnQsIFJFR19TQ19DVFJMX01PREUsDQo+ID4gKwkJCQkJ IFNDX0NUUkxfTU9ERV9TVFJFQU1JTkcpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50 IF9fb3YwMmExMF9zdG9wX3N0cmVhbShzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCkNCj4gPiArew0K PiA+ICsJc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92 MDJhMTAtPnN1YmRldik7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIGkyY19zbWJ1c193cml0ZV9ieXRl X2RhdGEoY2xpZW50LCBSRUdfU0NfQ1RSTF9NT0RFLA0KPiA+ICsJCQkJCSBTQ19DVFJMX01PREVf U1RBTkRCWSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9lbnRpdHlf aW5pdF9jZmcoc3RydWN0IHY0bDJfc3ViZGV2ICpzZCwNCj4gPiArCQkJCSAgIHN0cnVjdCB2NGwy X3N1YmRldl9wYWRfY29uZmlnICpjZmcpDQo+ID4gK3sNCj4gPiArCXN0cnVjdCB2NGwyX3N1YmRl dl9mb3JtYXQgZm10ID0gew0KPiA+ICsJCS53aGljaCA9IFY0TDJfU1VCREVWX0ZPUk1BVF9UUlks DQo+ID4gKwkJLmZvcm1hdCA9IHsNCj4gPiArCQkJLndpZHRoID0gMTYwMCwNCj4gPiArCQkJLmhl aWdodCA9IDEyMDAsDQo+ID4gKwkJfQ0KPiA+ICsJfTsNCj4gPiArDQo+ID4gKwlvdjAyYTEwX3Nl dF9mbXQoc2QsIGNmZywgJmZtdCk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4g PiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9zX3N0cmVhbShzdHJ1Y3QgdjRsMl9zdWJkZXYg KnNkLCBpbnQgb24pDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBvdjAyYTEwICpvdjAyYTEwID0gdG9f b3YwMmExMChzZCk7DQo+ID4gKwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50ID0gdjRsMl9nZXRf c3ViZGV2ZGF0YSgmb3YwMmExMC0+c3ViZGV2KTsNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ ICsJbXV0ZXhfbG9jaygmb3YwMmExMC0+bXV0ZXgpOw0KPiA+ICsNCj4gPiArCWlmIChvdjAyYTEw LT5zdHJlYW1pbmcgPT0gb24pDQo+ID4gKwkJZ290byB1bmxvY2tfYW5kX3JldHVybjsNCj4gPiAr DQo+ID4gKwlpZiAob24pIHsNCj4gPiArCQlyZXQgPSBwbV9ydW50aW1lX2dldF9zeW5jKCZjbGll bnQtPmRldik7DQo+ID4gKwkJaWYgKHJldCA8IDApIHsNCj4gPiArCQkJcG1fcnVudGltZV9wdXRf bm9pZGxlKCZjbGllbnQtPmRldik7DQo+ID4gKwkJCWdvdG8gdW5sb2NrX2FuZF9yZXR1cm47DQo+ ID4gKwkJfQ0KPiA+ICsNCj4gPiArCQlyZXQgPSBfX292MDJhMTBfc3RhcnRfc3RyZWFtKG92MDJh MTApOw0KPiA+ICsJCWlmIChyZXQpIHsNCj4gPiArCQkJX19vdjAyYTEwX3N0b3Bfc3RyZWFtKG92 MDJhMTApOw0KPiA+ICsJCQlvdjAyYTEwLT5zdHJlYW1pbmcgPSAhb247DQo+ID4gKwkJCWdvdG8g ZXJyX3JwbV9wdXQ7DQo+ID4gKwkJfQ0KPiA+ICsJfSBlbHNlIHsNCj4gPiArCQlfX292MDJhMTBf c3RvcF9zdHJlYW0ob3YwMmExMCk7DQo+ID4gKwkJcG1fcnVudGltZV9wdXQoJmNsaWVudC0+ZGV2 KTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlvdjAyYTEwLT5zdHJlYW1pbmcgPSBvbjsNCj4gPiAr CW11dGV4X3VubG9jaygmb3YwMmExMC0+bXV0ZXgpOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0K PiA+ICsNCj4gPiArZXJyX3JwbV9wdXQ6DQo+ID4gKwlwbV9ydW50aW1lX3B1dCgmY2xpZW50LT5k ZXYpOw0KPiA+ICt1bmxvY2tfYW5kX3JldHVybjoNCj4gPiArCW11dGV4X3VubG9jaygmb3YwMmEx MC0+bXV0ZXgpOw0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4g K3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29wcyBvdjAyYTEwX3BtX29wcyA9IHsNCj4gPiAr CVNFVF9TWVNURU1fU0xFRVBfUE1fT1BTKHBtX3J1bnRpbWVfZm9yY2Vfc3VzcGVuZCwNCj4gPiAr CQkJCXBtX3J1bnRpbWVfZm9yY2VfcmVzdW1lKQ0KPiA+ICsJU0VUX1JVTlRJTUVfUE1fT1BTKG92 MDJhMTBfcG93ZXJfb2ZmLCBvdjAyYTEwX3Bvd2VyX29uLCBOVUxMKQ0KPiA+ICt9Ow0KPiA+ICsN Cj4gPiArLyoNCj4gPiArICogb3YwMmExMF9zZXRfZXhwb3N1cmUgLSBGdW5jdGlvbiBjYWxsZWQg d2hlbiBzZXR0aW5nIGV4cG9zdXJlIHRpbWUNCj4gPiArICogQHByaXY6IFBvaW50ZXIgdG8gZGV2 aWNlIHN0cnVjdHVyZQ0KPiA+ICsgKiBAdmFsOiBWYXJpYWJsZSBmb3IgZXhwb3N1cmUgdGltZSwg aW4gdGhlIHVuaXQgb2YgbWljcm8tc2Vjb25kDQo+ID4gKyAqDQo+ID4gKyAqIFNldCBleHBvc3Vy ZSB0aW1lIGJhc2VkIG9uIGlucHV0IHZhbHVlLg0KPiA+ICsgKg0KPiA+ICsgKiBSZXR1cm46IDAg b24gc3VjY2Vzcw0KPiA+ICsgKi8NCj4gPiArc3RhdGljIGludCBvdjAyYTEwX3NldF9leHBvc3Vy ZShzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCwgaW50IHZhbCkNCj4gPiArew0KPiA+ICsJc3RydWN0 IGkyY19jbGllbnQgKmNsaWVudCA9IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92MDJhMTAtPnN1YmRl dik7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCXJldCA9IGkyY19zbWJ1c193cml0ZV9i eXRlX2RhdGEoY2xpZW50LCBSRUdfUEFHRV9TV0lUQ0gsIFJFR19FTkFCTEUpOw0KPiA+ICsJaWYg KHJldCA8IDApDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBpMmNfc21i dXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgT1YwMkExMF9SRUdfRVhQT1NVUkVfSCwNCj4gPiAr CQkJCQl2YWwgPj4gT1YwMkExMF9FWFBfU0hJRlQpOw0KPiA+ICsJaWYgKHJldCA8IDApDQo+ID4g KwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9k YXRhKGNsaWVudCwgT1YwMkExMF9SRUdfRVhQT1NVUkVfTCwgdmFsKTsNCj4gPiArCWlmIChyZXQg PCAwKQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIGkyY19zbWJ1c193 cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBSRUdfR0xPQkFMX0VGRkVDVElWRSwNCj4gPiArCQkJCQkg UkVHX0VOQUJMRSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9zZXRf Z2FpbihzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCwgaW50IHZhbCkNCj4gPiArew0KPiA+ICsJc3Ry dWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92MDJhMTAtPnN1 YmRldik7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCXJldCA9IGkyY19zbWJ1c193cml0 ZV9ieXRlX2RhdGEoY2xpZW50LCBSRUdfUEFHRV9TV0lUQ0gsIFJFR19FTkFCTEUpOw0KPiA+ICsJ aWYgKHJldCA8IDApDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBpMmNf c21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgT1YwMkExMF9SRUdfR0FJTiwgdmFsKTsNCj4g PiArCWlmIChyZXQgPCAwKQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJcmV0dXJu IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBSRUdfR0xPQkFMX0VGRkVDVElWRSwN Cj4gPiArCQkJCQkgUkVHX0VOQUJMRSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQg b3YwMmExMF9zZXRfdmJsYW5rKHN0cnVjdCBvdjAyYTEwICpvdjAyYTEwLCBpbnQgdmFsKQ0KPiA+ ICt7DQo+ID4gKwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50ID0gdjRsMl9nZXRfc3ViZGV2ZGF0 YSgmb3YwMmExMC0+c3ViZGV2KTsNCj4gPiArCXUzMiB2dHMgPSB2YWwgKyBvdjAyYTEwLT5jdXJf bW9kZS0+aGVpZ2h0IC0gT1YwMkExMF9CQVNJQ19MSU5FOw0KPiA+ICsJaW50IHJldDsNCj4gPiAr DQo+ID4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgUkVHX1BBR0Vf U1dJVENILCBSRUdfRU5BQkxFKTsNCj4gPiArCWlmIChyZXQgPCAwKQ0KPiA+ICsJCXJldHVybiBy ZXQ7DQo+ID4gKw0KPiA+ICsJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGVfZGF0YShjbGllbnQs IE9WMDJBMTBfUkVHX1ZUU19ILA0KPiA+ICsJCQkJCXZ0cyA+PiBPVjAyQTEwX1ZUU19TSElGVCk7 DQo+ID4gKwlpZiAocmV0IDwgMCkNCj4gPiArCQlyZXR1cm4gcmV0Ow0KPiA+ICsNCj4gPiArCXJl dCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBPVjAyQTEwX1JFR19WVFNfTCwg dnRzKTsNCj4gPiArCWlmIChyZXQgPCAwKQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ ICsJcmV0dXJuIGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBSRUdfR0xPQkFMX0VG RkVDVElWRSwNCj4gPiArCQkJCQkgUkVHX0VOQUJMRSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0 YXRpYyBpbnQgb3YwMmExMF9zZXRfdGVzdF9wYXR0ZXJuKHN0cnVjdCBvdjAyYTEwICpvdjAyYTEw LCBpbnQgcGF0dGVybikNCj4gPiArew0KPiA+ICsJc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9 IHY0bDJfZ2V0X3N1YmRldmRhdGEoJm92MDJhMTAtPnN1YmRldik7DQo+ID4gKwlpbnQgcmV0Ow0K PiA+ICsNCj4gPiArCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBSRUdf UEFHRV9TV0lUQ0gsIFJFR19FTkFCTEUpOw0KPiA+ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJcmV0 dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNs aWVudCwgT1YwMkExMF9SRUdfVEVTVF9QQVRURVJOLA0KPiA+ICsJCQkJCXBhdHRlcm4pOw0KPiA+ ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBp MmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgUkVHX0dMT0JBTF9FRkZFQ1RJVkUsDQo+ ID4gKwkJCQkJUkVHX0VOQUJMRSk7DQo+ID4gKwlpZiAocmV0IDwgMCkNCj4gPiArCQlyZXR1cm4g cmV0Ow0KPiA+ICsNCj4gPiArCXJldHVybiBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVu dCwgUkVHX1NDX0NUUkxfTU9ERSwNCj4gPiArCQkJCQkgU0NfQ1RSTF9NT0RFX1NUUkVBTUlORyk7 DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9zZXRfY3RybChzdHJ1Y3Qg djRsMl9jdHJsICpjdHJsKQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCA9 IGNvbnRhaW5lcl9vZihjdHJsLT5oYW5kbGVyLA0KPiA+ICsJCQkJCSAgICAgICBzdHJ1Y3Qgb3Yw MmExMCwgY3RybF9oYW5kbGVyKTsNCj4gPiArCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSB2 NGwyX2dldF9zdWJkZXZkYXRhKCZvdjAyYTEwLT5zdWJkZXYpOw0KPiA+ICsJczY0IG1heF9leHBv Ow0KPiA+ICsJaW50IHJldDsNCj4gPiArDQo+ID4gKwkvKiBQcm9wYWdhdGUgY2hhbmdlIG9mIGN1 cnJlbnQgY29udHJvbCB0byBhbGwgcmVsYXRlZCBjb250cm9scyAqLw0KPiA+ICsJaWYgKGN0cmwt PmlkID09IFY0TDJfQ0lEX1ZCTEFOSykgew0KPiA+ICsJCS8qIFVwZGF0ZSBtYXggZXhwb3N1cmUg d2hpbGUgbWVldGluZyBleHBlY3RlZCB2YmxhbmtpbmcgKi8NCj4gPiArCQltYXhfZXhwbyA9IG92 MDJhMTAtPmN1cl9tb2RlLT5oZWlnaHQgKyBjdHJsLT52YWwgLQ0KPiA+ICsJCQkgICBPVjAyQTEw X0VYUE9TVVJFX01BWF9NQVJHSU47DQo+ID4gKwkJX192NGwyX2N0cmxfbW9kaWZ5X3JhbmdlKG92 MDJhMTAtPmV4cG9zdXJlLA0KPiA+ICsJCQkJCSBvdjAyYTEwLT5leHBvc3VyZS0+bWluaW11bSwg bWF4X2V4cG8sDQo+ID4gKwkJCQkJIG92MDJhMTAtPmV4cG9zdXJlLT5zdGVwLA0KPiA+ICsJCQkJ CSBvdjAyYTEwLT5leHBvc3VyZS0+ZGVmYXVsdF92YWx1ZSk7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ ICsJLyogVjRMMiBjb250cm9scyB2YWx1ZXMgd2lsbCBiZSBhcHBsaWVkIG9ubHkgd2hlbiBwb3dl ciBpcyBhbHJlYWR5IHVwICovDQo+ID4gKwlpZiAoIXBtX3J1bnRpbWVfZ2V0X2lmX2luX3VzZSgm Y2xpZW50LT5kZXYpKQ0KPiA+ICsJCXJldHVybiAwOw0KPiA+ICsNCj4gPiArCXN3aXRjaCAoY3Ry bC0+aWQpIHsNCj4gPiArCWNhc2UgVjRMMl9DSURfRVhQT1NVUkU6DQo+ID4gKwkJcmV0ID0gb3Yw MmExMF9zZXRfZXhwb3N1cmUob3YwMmExMCwgY3RybC0+dmFsKTsNCj4gPiArCQlicmVhazsNCj4g PiArCWNhc2UgVjRMMl9DSURfQU5BTE9HVUVfR0FJTjoNCj4gPiArCQlyZXQgPSBvdjAyYTEwX3Nl dF9nYWluKG92MDJhMTAsIGN0cmwtPnZhbCk7DQo+ID4gKwkJYnJlYWs7DQo+ID4gKwljYXNlIFY0 TDJfQ0lEX1ZCTEFOSzoNCj4gPiArCQlyZXQgPSBvdjAyYTEwX3NldF92Ymxhbmsob3YwMmExMCwg Y3RybC0+dmFsKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWNhc2UgVjRMMl9DSURfVEVTVF9QQVRU RVJOOg0KPiA+ICsJCXJldCA9IG92MDJhMTBfc2V0X3Rlc3RfcGF0dGVybihvdjAyYTEwLCBjdHJs LT52YWwpOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJZGVmYXVsdDoNCj4gPiArCQlyZXQgPSAtRUlO VkFMOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJfTsNCj4gPiArDQo+ID4gKwlwbV9ydW50aW1lX3B1 dCgmY2xpZW50LT5kZXYpOw0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiAr DQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdjRsMl9zdWJkZXZfdmlkZW9fb3BzIG92MDJhMTBf dmlkZW9fb3BzID0gew0KPiA+ICsJLnNfc3RyZWFtID0gb3YwMmExMF9zX3N0cmVhbSwNCj4gPiAr fTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdjRsMl9zdWJkZXZfcGFkX29wcyBv djAyYTEwX3BhZF9vcHMgPSB7DQo+ID4gKwkuaW5pdF9jZmcgPSBvdjAyYTEwX2VudGl0eV9pbml0 X2NmZywNCj4gPiArCS5lbnVtX21idXNfY29kZSA9IG92MDJhMTBfZW51bV9tYnVzX2NvZGUsDQo+ ID4gKwkuZW51bV9mcmFtZV9zaXplID0gb3YwMmExMF9lbnVtX2ZyYW1lX3NpemVzLA0KPiA+ICsJ LmdldF9mbXQgPSBvdjAyYTEwX2dldF9mbXQsDQo+ID4gKwkuc2V0X2ZtdCA9IG92MDJhMTBfc2V0 X2ZtdCwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdjRsMl9zdWJk ZXZfb3BzIG92MDJhMTBfc3ViZGV2X29wcyA9IHsNCj4gPiArCS52aWRlbwk9ICZvdjAyYTEwX3Zp ZGVvX29wcywNCj4gPiArCS5wYWQJPSAmb3YwMmExMF9wYWRfb3BzLA0KPiA+ICt9Ow0KPiA+ICsN Cj4gPiArc3RhdGljIGNvbnN0IHN0cnVjdCBtZWRpYV9lbnRpdHlfb3BlcmF0aW9ucyBvdjAyYTEw X3N1YmRldl9lbnRpdHlfb3BzID0gew0KPiA+ICsJLmxpbmtfdmFsaWRhdGUgPSB2NGwyX3N1YmRl dl9saW5rX3ZhbGlkYXRlLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0cnVj dCB2NGwyX2N0cmxfb3BzIG92MDJhMTBfY3RybF9vcHMgPSB7DQo+ID4gKwkuc19jdHJsID0gb3Yw MmExMF9zZXRfY3RybCwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9p bml0aWFsaXplX2NvbnRyb2xzKHN0cnVjdCBvdjAyYTEwICpvdjAyYTEwKQ0KPiA+ICt7DQo+ID4g KwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50ID0gdjRsMl9nZXRfc3ViZGV2ZGF0YSgmb3YwMmEx MC0+c3ViZGV2KTsNCj4gPiArCWNvbnN0IHN0cnVjdCBvdjAyYTEwX21vZGUgKm1vZGU7DQo+ID4g KwlzdHJ1Y3QgdjRsMl9jdHJsX2hhbmRsZXIgKmhhbmRsZXI7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9j dHJsICpjdHJsOw0KPiA+ICsJczY0IGV4cG9zdXJlX21heDsNCj4gPiArCXM2NCB2YmxhbmtfZGVm Ow0KPiA+ICsJczY0IHBpeGVsX3JhdGU7DQo+ID4gKwlzNjQgaF9ibGFuazsNCj4gPiArCWludCBy ZXQ7DQo+ID4gKw0KPiA+ICsJaGFuZGxlciA9ICZvdjAyYTEwLT5jdHJsX2hhbmRsZXI7DQo+ID4g Kwltb2RlID0gb3YwMmExMC0+Y3VyX21vZGU7DQo+ID4gKwlyZXQgPSB2NGwyX2N0cmxfaGFuZGxl cl9pbml0KGhhbmRsZXIsIDcpOw0KPiA+ICsJaWYgKHJldCkNCj4gPiArCQlyZXR1cm4gcmV0Ow0K PiA+ICsNCj4gPiArCWhhbmRsZXItPmxvY2sgPSAmb3YwMmExMC0+bXV0ZXg7DQo+ID4gKw0KPiA+ ICsJY3RybCA9IHY0bDJfY3RybF9uZXdfaW50X21lbnUoaGFuZGxlciwgTlVMTCwgVjRMMl9DSURf TElOS19GUkVRLCAwLCAwLA0KPiA+ICsJCQkJICAgICAgbGlua19mcmVxX21lbnVfaXRlbXMpOw0K PiA+ICsJaWYgKGN0cmwpDQo+ID4gKwkJY3RybC0+ZmxhZ3MgfD0gVjRMMl9DVFJMX0ZMQUdfUkVB RF9PTkxZOw0KPiA+ICsNCj4gPiArCXBpeGVsX3JhdGUgPSB0b19waXhlbF9yYXRlKDApOw0KPiA+ ICsJdjRsMl9jdHJsX25ld19zdGQoaGFuZGxlciwgTlVMTCwgVjRMMl9DSURfUElYRUxfUkFURSwg MCwgcGl4ZWxfcmF0ZSwgMSwNCj4gPiArCQkJICBwaXhlbF9yYXRlKTsNCj4gPiArDQo+ID4gKwlo X2JsYW5rID0gbW9kZS0+aHRzX2RlZiAtIG1vZGUtPndpZHRoOw0KPiA+ICsJdjRsMl9jdHJsX25l d19zdGQoaGFuZGxlciwgTlVMTCwgVjRMMl9DSURfSEJMQU5LLCBoX2JsYW5rLCBoX2JsYW5rLCAx LA0KPiA+ICsJCQkgIGhfYmxhbmspOw0KPiA+ICsNCj4gPiArCXZibGFua19kZWYgPSBtb2RlLT52 dHNfZGVmIC0gbW9kZS0+aGVpZ2h0Ow0KPiA+ICsJdjRsMl9jdHJsX25ld19zdGQoaGFuZGxlciwg Jm92MDJhMTBfY3RybF9vcHMsIFY0TDJfQ0lEX1ZCTEFOSywNCj4gPiArCQkJICB2YmxhbmtfZGVm LCBPVjAyQTEwX1ZUU19NQVggLSBtb2RlLT5oZWlnaHQsIDEsDQo+ID4gKwkJCSAgdmJsYW5rX2Rl Zik7DQo+ID4gKw0KPiA+ICsJZXhwb3N1cmVfbWF4ID0gbW9kZS0+dnRzX2RlZiAtIDQ7DQo+ID4g KwlvdjAyYTEwLT5leHBvc3VyZSA9IHY0bDJfY3RybF9uZXdfc3RkKGhhbmRsZXIsICZvdjAyYTEw X2N0cmxfb3BzLA0KPiA+ICsJCQkJCSAgICAgIFY0TDJfQ0lEX0VYUE9TVVJFLA0KPiA+ICsJCQkJ CSAgICAgIE9WMDJBMTBfRVhQT1NVUkVfTUlOLA0KPiA+ICsJCQkJCSAgICAgIGV4cG9zdXJlX21h eCwNCj4gPiArCQkJCQkgICAgICBPVjAyQTEwX0VYUE9TVVJFX1NURVAsDQo+ID4gKwkJCQkJICAg ICAgbW9kZS0+ZXhwX2RlZik7DQo+ID4gKw0KPiA+ICsJdjRsMl9jdHJsX25ld19zdGQoaGFuZGxl ciwgJm92MDJhMTBfY3RybF9vcHMsDQo+ID4gKwkJCSAgVjRMMl9DSURfQU5BTE9HVUVfR0FJTiwg T1YwMkExMF9HQUlOX01JTiwNCj4gPiArCQkJICBPVjAyQTEwX0dBSU5fTUFYLCBPVjAyQTEwX0dB SU5fU1RFUCwNCj4gPiArCQkJICBPVjAyQTEwX0dBSU5fREVGQVVMVCk7DQo+ID4gKw0KPiA+ICsJ djRsMl9jdHJsX25ld19zdGRfbWVudV9pdGVtcyhoYW5kbGVyLCAmb3YwMmExMF9jdHJsX29wcywN Cj4gPiArCQkJCSAgICAgVjRMMl9DSURfVEVTVF9QQVRURVJOLA0KPiA+ICsJCQkJICAgICBBUlJB WV9TSVpFKG92MDJhMTBfdGVzdF9wYXR0ZXJuX21lbnUpIC0gMSwNCj4gPiArCQkJCSAgICAgMCwg MCwgb3YwMmExMF90ZXN0X3BhdHRlcm5fbWVudSk7DQo+ID4gKw0KPiA+ICsJaWYgKGhhbmRsZXIt PmVycm9yKSB7DQo+ID4gKwkJcmV0ID0gaGFuZGxlci0+ZXJyb3I7DQo+ID4gKwkJZGV2X2Vycigm Y2xpZW50LT5kZXYsICJmYWlsZWQgdG8gaW5pdCBjb250cm9scyglZClcbiIsIHJldCk7DQo+ID4g KwkJZ290byBlcnJfZnJlZV9oYW5kbGVyOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCW92MDJhMTAt PnN1YmRldi5jdHJsX2hhbmRsZXIgPSBoYW5kbGVyOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0K PiA+ICsNCj4gPiArZXJyX2ZyZWVfaGFuZGxlcjoNCj4gPiArCXY0bDJfY3RybF9oYW5kbGVyX2Zy ZWUoaGFuZGxlcik7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4g PiArc3RhdGljIGludCBvdjAyYTEwX2NoZWNrX2h3Y2ZnKHN0cnVjdCBkZXZpY2UgKmRldiwgc3Ry dWN0IG92MDJhMTAgKm92MDJhMTApDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBmd25vZGVfaGFuZGxl ICplcDsNCj4gPiArCXN0cnVjdCBmd25vZGVfaGFuZGxlICpmd25vZGUgPSBkZXZfZndub2RlKGRl dik7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9md25vZGVfZW5kcG9pbnQgYnVzX2NmZyA9IHsNCj4gPiAr CQkuYnVzX3R5cGUgPSBWNEwyX01CVVNfQ1NJMl9EUEhZLA0KPiA+ICsJfTsNCj4gPiArCXVuc2ln bmVkIGludCBpLCBqOw0KPiA+ICsJaW50IHJldDsNCj4gPiArDQo+ID4gKwlpZiAoIWZ3bm9kZSkN Cj4gPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gPiArDQo+ID4gKwllcCA9IGZ3bm9kZV9ncmFwaF9n ZXRfbmV4dF9lbmRwb2ludChmd25vZGUsIE5VTEwpOw0KPiA+ICsJaWYgKCFlcCkNCj4gPiArCQly ZXR1cm4gLUVOWElPOw0KPiA+ICsNCj4gPiArCXJldCA9IHY0bDJfZndub2RlX2VuZHBvaW50X2Fs bG9jX3BhcnNlKGVwLCAmYnVzX2NmZyk7DQo+ID4gKwlmd25vZGVfaGFuZGxlX3B1dChlcCk7DQo+ ID4gKwlpZiAocmV0KQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJaWYgKCFidXNf Y2ZnLm5yX29mX2xpbmtfZnJlcXVlbmNpZXMpIHsNCj4gPiArCQlkZXZfZXJyKGRldiwgIm5vIGxp bmsgZnJlcXVlbmNpZXMgZGVmaW5lZFxuIik7DQo+ID4gKwkJcmV0ID0gLUVJTlZBTDsNCj4gPiAr CQlnb3RvIGNoZWNrX2h3Y2ZnX2Vycm9yOw0KPiA+ICsJfQ0KPiANCj4gSWYgaXQncyAwLCB0aGUg YmVsb3cgd2lsbCBicmVhayBvbiAnaWYgKGogPT0gMCknIHdpdGggc2xpZ2h0bHkgZGlmZmVyZW50 IGJ1dA0KPiBpbmZvcm1hdGl2ZSBlbm91Z2ggbWVzc2FnZS4gV2hhdCBkbyB5b3Uga2VlcCBhYm92 ZSBjaGVjayBmb3I/DQo+IA0KDQpJIHN0aWxsIHByZWZlciB0byB0aGUgb3JpZ2luYWwgdmVyc2lv bi4NCklmICdidXNfY2ZnLm5yX29mX2xpbmtfZnJlcXVlbmNpZXMnIGlzIDAsIHNob3VsZG4ndCB3 ZSBkaXJlY3RseSByZXR1cm4NCmVycm9yPw0KDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgQVJSQVlf U0laRShsaW5rX2ZyZXFfbWVudV9pdGVtcyk7IGkrKykgew0KPiA+ICsJCWZvciAoaiA9IDA7IGog PCBidXNfY2ZnLm5yX29mX2xpbmtfZnJlcXVlbmNpZXM7IGorKykgew0KPiA+ICsJCQlpZiAobGlu a19mcmVxX21lbnVfaXRlbXNbaV0gPT0NCj4gPiArCQkJCWJ1c19jZmcubGlua19mcmVxdWVuY2ll c1tqXSkgew0KPiA+ICsJCQkJb3YwMmExMC0+ZnJlcV9pbmRleCA9IGk7DQo+ID4gKwkJCQlicmVh azsNCj4gPiArCQkJfQ0KPiA+ICsJCX0NCj4gPiArDQo+ID4gKwkJaWYgKGogPT0gYnVzX2NmZy5u cl9vZl9saW5rX2ZyZXF1ZW5jaWVzKSB7DQo+ID4gKwkJCWRldl9lcnIoZGV2LCAibm8gbGluayBm cmVxdWVuY3kgJWxsZCBzdXBwb3J0ZWRcbiIsDQo+ID4gKwkJCQlsaW5rX2ZyZXFfbWVudV9pdGVt c1tpXSk7DQo+ID4gKwkJCXJldCA9IC1FSU5WQUw7DQo+IA0KPiA+ICsJCQlnb3RvIGNoZWNrX2h3 Y2ZnX2Vycm9yOw0KPiANCj4gJ2JyZWFrOycgd29uJ3Qgd29yaz8NCj4gDQo+ID4gKwkJfQ0KPiA+ ICsJfQ0KPiA+ICsNCj4gPiArY2hlY2tfaHdjZmdfZXJyb3I6DQo+IA0KPiBvdXRfZW5kcG9pbnRf ZnJlZToNCj4gDQoNCkl0IHNlZW1zIHRoYXQgT1Y4ODU2IGtlZXBzIHRoZSBzYW1lIHBhdHRlcm4u DQoNCj4gPiArCXY0bDJfZndub2RlX2VuZHBvaW50X2ZyZWUoJmJ1c19jZmcpOw0KPiA+ICsNCj4g PiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgb3YwMmExMF9w cm9iZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGV2 aWNlICpkZXYgPSAmY2xpZW50LT5kZXY7DQo+ID4gKwlzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMDsN Cj4gPiArCXVuc2lnbmVkIGludCByb3RhdGlvbjsNCj4gPiArCXVuc2lnbmVkIGludCBjbnQgPSAw Ow0KPiA+ICsJdW5zaWduZWQgaW50IGk7DQo+IA0KPiA+ICsJdW5zaWduZWQgaW50IG51bV9mcmVx X2Nsa192b2x0ID0gMiAqIEFSUkFZX1NJWkUobGlua19mcmVxX21lbnVfaXRlbXMpOw0KPiANCj4g Q2FuIGl0IGJlIG1vdmVkIHVwcGVyIHRvIGltcHJvdmUgcmVhZGFiaWxpdHk/DQo+IA0KDQpGaXhl ZCBpbiBuZXh0IHJlbGVhc2UuDQoNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJb3YwMmEx MCA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqb3YwMmExMCksIEdGUF9LRVJORUwpOw0KPiA+ ICsJaWYgKCFvdjAyYTEwKQ0KPiA+ICsJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsNCj4gPiArCXJl dCA9IG92MDJhMTBfY2hlY2tfaHdjZmcoZGV2LCBvdjAyYTEwKTsNCj4gPiArCWlmIChyZXQpIHsN Cj4gPiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBjaGVjayBIVyBjb25maWd1cmF0aW9uOiAl ZFxuIiwgcmV0KTsNCj4gPiArCQlyZXR1cm4gcmV0Ow0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXY0 bDJfaTJjX3N1YmRldl9pbml0KCZvdjAyYTEwLT5zdWJkZXYsIGNsaWVudCwgJm92MDJhMTBfc3Vi ZGV2X29wcyk7DQo+ID4gKwlvdjAyYTEwLT5taXBpX2Nsb2NrX3ZvbHRhZ2UgPSBPVjAyQTEwX01J UElfVFhfU1BFRURfREVGQVVMVDsNCj4gPiArCW92MDJhMTAtPmZtdC5jb2RlID0gTUVESUFfQlVT X0ZNVF9TQkdHUjEwXzFYMTA7DQo+ID4gKw0KPiA+ICsJLyogT3B0aW9uYWwgaW5kaWNhdGlvbiBv ZiBwaHlzaWNhbCByb3RhdGlvbiBvZiBzZW5zb3IgKi8NCj4gPiArCXJldCA9IGZ3bm9kZV9wcm9w ZXJ0eV9yZWFkX3UzMihkZXZfZndub2RlKGRldiksICJyb3RhdGlvbiIsICZyb3RhdGlvbik7DQo+ ID4gKwlpZiAoIXJldCAmJiByb3RhdGlvbiA9PSAxODApIHsNCj4gDQo+IENhbiBiZSBzaW1wbGlm aWVkIChidXQgSSdtIGZpbmUgd2l0aCBhYm92ZSk6DQo+IA0KPiAJdW5zaWduZWQgaW50IHJvdGF0 aW9uID0gMDsNCj4gCS4uLg0KPiAJZndub2RlX3Byb3BlcnR5X3JlYWRfdTMyKC4uLiwgJnJvdGF0 aW9uKTsNCj4gCWlmIChyb3RhdGlvbiA9PSAxODApIHsNCj4gCQkuLi4NCj4gCX0NCj4gDQoNClNv dW5kcyBsaWtlIHRoZSByZWFkYWJpbGl0eSBpcyBpbXByb3ZlZCB1c2luZyB0aGUgbGF0dGVyIHN0 eWxlIDotKQ0KDQo+ID4gKwkJb3YwMmExMC0+dXBzaWRlX2Rvd24gPSB0cnVlOw0KPiA+ICsJCW92 MDJhMTAtPmZtdC5jb2RlID0gTUVESUFfQlVTX0ZNVF9TUkdHQjEwXzFYMTA7DQo+ID4gKwl9DQo+ ID4gKw0KPiA+ICsJLyogT3B0aW9uYWwgaW5kaWNhdGlvbiBvZiBNSVBJIGNsb2NrIHZvbHRhZ2Ug dW5pdCAqLw0KPiA+ICsJcmV0ID0gZndub2RlX3Byb3BlcnR5X3JlYWRfdTMyX2FycmF5KGRldl9m d25vZGUoZGV2KSwNCj4gPiArCQkJCQkgICAgICJvdnRpLG1pcGktY2xvY2stdm9sdGFnZSIsIE5V TEwsDQo+ID4gKwkJCQkJICAgICAwKTsNCj4gDQo+IAlyZXQgPSBmd25vZGVfcHJvcGVydHlfY291 bnRfdTMyKC4uLik7IC8vIHdpbGwgYmUgb25lIGxpbmUNCj4gDQoNCkdyZWF0IEFQSXMhDQoNCj4g PiArCWlmIChyZXQgPiAwICYmIHJldCAlIDIgPT0gMCkgew0KPiA+ICsJCXUzMiBmcmVxX2Nsa192 b2x0W3JldF07DQo+ID4gKw0KPiA+ICsJCWZ3bm9kZV9wcm9wZXJ0eV9yZWFkX3UzMl9hcnJheShk ZXZfZndub2RlKGRldiksDQo+ID4gKwkJCQkJICAgICAgICJvdnRpLG1pcGktY2xvY2stdm9sdGFn ZSIsDQo+ID4gKwkJCQkJICAgICAgIGZyZXFfY2xrX3ZvbHQsDQo+ID4gKwkJCQkJICAgICAgIEFS UkFZX1NJWkUoZnJlcV9jbGtfdm9sdCkpOw0KPiA+ICsNCj4gPiArCQl3aGlsZSAobnVtX2ZyZXFf Y2xrX3ZvbHQpIHsNCj4gPiArCQkJdW5zaWduZWQgbG9uZyBmcmVxOw0KPiA+ICsJCQl1bnNpZ25l ZCBsb25nIHZvbHQ7DQo+ID4gKw0KPiA+ICsJCQlpZiAoY250ID49IEFSUkFZX1NJWkUoZnJlcV9j bGtfdm9sdCkpIHsNCj4gPiArCQkJCWRldl93YXJuKGRldiwgIm1pc21hdGNoZWQgbGluayBmcmVx dWVuY3lcbiIpOw0KPiA+ICsJCQkJYnJlYWs7DQo+ID4gKwkJCX0NCj4gPiArDQo+IA0KPiA+ICsJ CQlmcmVxID0gZnJlcV9jbGtfdm9sdFtjbnQrK10gKiAxMDAwOw0KPiANCj4gSFpfUEVSX0tIWj8N Cj4gDQoNCkZpeGVkIGluIG5leHQgcmVsZWFzZS4NCg0KPiA+ICsJCQl2b2x0ID0gZnJlcV9jbGtf dm9sdFtjbnQrK107DQo+ID4gKw0KPiA+ICsJCQkvKiBHZXQgY2xvY2sgdm9sdGFnZSB1bml0IHZh bHVlIGZyb20gRFQgKi8NCj4gPiArCQkJaWYgKGZyZXEgPT0gbGlua19mcmVxX21lbnVfaXRlbXNb b3YwMmExMC0+ZnJlcV9pbmRleF0pIHsNCj4gPiArCQkJCW92MDJhMTAtPm1pcGlfY2xvY2tfdm9s dGFnZSA9IHZvbHQ7DQo+ID4gKwkJCQlicmVhazsNCj4gPiArCQkJfQ0KPiA+ICsNCj4gPiArCQkJ bnVtX2ZyZXFfY2xrX3ZvbHQgLT0gMjsNCj4gPiArCQl9DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJ LyogR2V0IGV4dGVybmFsIGlucHV0IGNsb2NrIChlY2xrKSAqLw0KPiA+ICsJb3YwMmExMC0+ZWNs ayA9IGRldm1fY2xrX2dldChkZXYsICJlY2xrIik7DQo+ID4gKwlpZiAoSVNfRVJSKG92MDJhMTAt PmVjbGspKSB7DQo+ID4gKwkJcmV0ID0gUFRSX0VSUihvdjAyYTEwLT5lY2xrKTsNCj4gPiArCQlk ZXZfZXJyKGRldiwgImZhaWxlZCB0byBnZXQgZWNsayAlZFxuIiwgcmV0KTsNCj4gPiArCQlyZXR1 cm4gcmV0Ow0KPiANCj4gCXJldHVybiBkZXZfZXJyX3Byb2JlKC4uLik7DQo+IA0KDQpHcmVhdCBB UElzLi4uDQoNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlyZXQgPSBmd25vZGVfcHJvcGVydHlfcmVh ZF91MzIoZGV2X2Z3bm9kZShkZXYpLCAiY2xvY2stZnJlcXVlbmN5IiwNCj4gPiArCQkJCSAgICAg ICAmb3YwMmExMC0+ZWNsa19mcmVxKTsNCj4gPiArCWlmIChyZXQpIHsNCj4gPiArCQlkZXZfZXJy KGRldiwgImZhaWxlZCB0byBnZXQgZWNsayBmcmVxdWVuY3lcbiIpOw0KPiA+ICsJCXJldHVybiBy ZXQ7DQo+ID4gKwl9DQo+IA0KPiA+ICsJcmV0ID0gY2xrX3NldF9yYXRlKG92MDJhMTAtPmVjbGss IG92MDJhMTAtPmVjbGtfZnJlcSk7DQo+ID4gKwlpZiAocmV0KSB7DQo+ID4gKwkJZGV2X2Vycihk ZXYsICJmYWlsZWQgdG8gc2V0IGVjbGsgZnJlcXVlbmN5ICgyNE1IeilcbiIpOw0KPiA+ICsJCXJl dHVybiByZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJaWYgKGNsa19nZXRfcmF0ZShvdjAyYTEw LT5lY2xrKSAhPSBPVjAyQTEwX0VDTEtfRlJFUSkgew0KPiA+ICsJCWRldl93YXJuKGRldiwgImVj bGsgbWlzbWF0Y2hlZCwgbW9kZSBpcyBiYXNlZCBvbiAyNE1IelxuIik7DQo+ID4gKwkJcmV0dXJu IC1FSU5WQUw7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJb3YwMmExMC0+cGRfZ3BpbyA9IGRldm1f Z3Bpb2RfZ2V0KGRldiwgInBvd2VyZG93biIsIEdQSU9EX09VVF9ISUdIKTsNCj4gPiArCWlmIChJ U19FUlIob3YwMmExMC0+cGRfZ3BpbykpIHsNCj4gDQo+ID4gKwkJcmV0ID0gUFRSX0VSUihvdjAy YTEwLT5wZF9ncGlvKTsNCj4gPiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBnZXQgcG93ZXJk b3duLWdwaW9zICVkXG4iLCByZXQpOw0KPiA+ICsJCXJldHVybiByZXQ7DQo+IA0KPiAJcmV0dXJu IGRldl9lcnJfcHJvYmUoLi4uKTsNCj4gDQoNCkl0IHdvdWxkIGJlIHNpbXBsaWZpZWQgdXNpbmcg ZGV2X2Vycl9wcm9iZSBkaXJlY3RseSBpbiBuZXh0IHJlbGVhc2UuDQoNCj4gPiArCX0NCj4gPiAr DQo+ID4gKwlvdjAyYTEwLT5yc3RfZ3BpbyA9IGRldm1fZ3Bpb2RfZ2V0KGRldiwgInJlc2V0Iiwg R1BJT0RfT1VUX0hJR0gpOw0KPiA+ICsJaWYgKElTX0VSUihvdjAyYTEwLT5yc3RfZ3BpbykpIHsN Cj4gPiArCQlyZXQgPSBQVFJfRVJSKG92MDJhMTAtPnJzdF9ncGlvKTsNCj4gPiArCQlkZXZfZXJy KGRldiwgImZhaWxlZCB0byBnZXQgcmVzZXQtZ3Bpb3MgJWRcbiIsIHJldCk7DQo+ID4gKwkJcmV0 dXJuIHJldDsNCj4gDQo+IERpdHRvLg0KPiANCg0KRml4ZWQgaW4gbmV4dCByZWxlYXNlLg0KDQo+ ID4gKwl9DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUob3YwMmExMF9z dXBwbHlfbmFtZXMpOyBpKyspDQo+ID4gKwkJb3YwMmExMC0+c3VwcGxpZXNbaV0uc3VwcGx5ID0g b3YwMmExMF9zdXBwbHlfbmFtZXNbaV07DQo+ID4gKw0KPiA+ICsJcmV0ID0gZGV2bV9yZWd1bGF0 b3JfYnVsa19nZXQoZGV2LCBBUlJBWV9TSVpFKG92MDJhMTBfc3VwcGx5X25hbWVzKSwNCj4gPiAr CQkJCSAgICAgIG92MDJhMTAtPnN1cHBsaWVzKTsNCj4gPiArCWlmIChyZXQpIHsNCj4gDQo+ID4g KwkJZGV2X2VycihkZXYsICJmYWlsZWQgdG8gZ2V0IHJlZ3VsYXRvcnNcbiIpOw0KPiA+ICsJCXJl dHVybiByZXQ7DQo+IA0KPiBEaXR0by4NCj4gDQoNCkZpeGVkIGluIG5leHQgcmVsZWFzZS4NCg0K PiA+ICsJfQ0KPiA+ICsNCj4gPiArCW11dGV4X2luaXQoJm92MDJhMTAtPm11dGV4KTsNCj4gPiAr CW92MDJhMTAtPmN1cl9tb2RlID0gJnN1cHBvcnRlZF9tb2Rlc1swXTsNCj4gPiArDQo+ID4gKwly ZXQgPSBvdjAyYTEwX2luaXRpYWxpemVfY29udHJvbHMob3YwMmExMCk7DQo+ID4gKwlpZiAocmV0 KSB7DQo+ID4gKwkJZGV2X2VycihkZXYsICJmYWlsZWQgdG8gaW5pdGlhbGl6ZSBjb250cm9sc1xu Iik7DQo+ID4gKwkJZ290byBlcnJfZGVzdHJveV9tdXRleDsNCj4gPiArCX0NCj4gPiArDQo+ID4g KwlvdjAyYTEwLT5zdWJkZXYuZmxhZ3MgfD0gVjRMMl9TVUJERVZfRkxfSEFTX0RFVk5PREU7DQo+ ID4gKwlvdjAyYTEwLT5zdWJkZXYuZW50aXR5Lm9wcyA9ICZvdjAyYTEwX3N1YmRldl9lbnRpdHlf b3BzOw0KPiA+ICsJb3YwMmExMC0+c3ViZGV2LmVudGl0eS5mdW5jdGlvbiA9IE1FRElBX0VOVF9G X0NBTV9TRU5TT1I7DQo+ID4gKwlvdjAyYTEwLT5wYWQuZmxhZ3MgPSBNRURJQV9QQURfRkxfU09V UkNFOw0KPiA+ICsNCj4gPiArCXJldCA9IG1lZGlhX2VudGl0eV9wYWRzX2luaXQoJm92MDJhMTAt PnN1YmRldi5lbnRpdHksIDEsICZvdjAyYTEwLT5wYWQpOw0KPiA+ICsJaWYgKHJldCA8IDApIHsN Cj4gPiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBpbml0IGVudGl0eSBwYWRzOiAlZCIsIHJl dCk7DQo+ID4gKwkJZ290byBlcnJfZnJlZV9oYW5kbGVyOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiAr CXBtX3J1bnRpbWVfZW5hYmxlKGRldik7DQo+ID4gKwlpZiAoIXBtX3J1bnRpbWVfZW5hYmxlZChk ZXYpKSB7DQo+ID4gKwkJcmV0ID0gb3YwMmExMF9wb3dlcl9vbihkZXYpOw0KPiA+ICsJCWlmIChy ZXQgPCAwKSB7DQo+ID4gKwkJCWRldl9lcnIoZGV2LCAiZmFpbGVkIHRvIHBvd2VyIG9uOiAlZFxu IiwgcmV0KTsNCj4gPiArCQkJZ290byBlcnJfY2xlYW5fZW50aXR5Ow0KPiA+ICsJCX0NCj4gPiAr CX0NCj4gPiArDQo+ID4gKwlyZXQgPSB2NGwyX2FzeW5jX3JlZ2lzdGVyX3N1YmRldigmb3YwMmEx MC0+c3ViZGV2KTsNCj4gPiArCWlmIChyZXQpIHsNCj4gPiArCQlkZXZfZXJyKGRldiwgImZhaWxl ZCB0byByZWdpc3RlciBWNEwyIHN1YmRldjogJWRcbiIsIHJldCk7DQo+ID4gKwkJZ290byBlcnJf cG93ZXJfb2ZmOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICsNCj4gPiAr ZXJyX3Bvd2VyX29mZjoNCj4gPiArCWlmIChwbV9ydW50aW1lX2VuYWJsZWQoZGV2KSkNCj4gPiAr CQlwbV9ydW50aW1lX2Rpc2FibGUoZGV2KTsNCj4gPiArCWVsc2UNCj4gPiArCQlvdjAyYTEwX3Bv d2VyX29mZihkZXYpOw0KPiA+ICtlcnJfY2xlYW5fZW50aXR5Og0KPiA+ICsJbWVkaWFfZW50aXR5 X2NsZWFudXAoJm92MDJhMTAtPnN1YmRldi5lbnRpdHkpOw0KPiA+ICtlcnJfZnJlZV9oYW5kbGVy Og0KPiA+ICsJdjRsMl9jdHJsX2hhbmRsZXJfZnJlZShvdjAyYTEwLT5zdWJkZXYuY3RybF9oYW5k bGVyKTsNCj4gPiArZXJyX2Rlc3Ryb3lfbXV0ZXg6DQo+ID4gKwltdXRleF9kZXN0cm95KCZvdjAy YTEwLT5tdXRleCk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4g PiArc3RhdGljIGludCBvdjAyYTEwX3JlbW92ZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KQ0K PiA+ICt7DQo+ID4gKwlzdHJ1Y3QgdjRsMl9zdWJkZXYgKnNkID0gaTJjX2dldF9jbGllbnRkYXRh KGNsaWVudCk7DQo+ID4gKwlzdHJ1Y3Qgb3YwMmExMCAqb3YwMmExMCA9IHRvX292MDJhMTAoc2Qp Ow0KPiA+ICsNCj4gPiArCXY0bDJfYXN5bmNfdW5yZWdpc3Rlcl9zdWJkZXYoc2QpOw0KPiA+ICsJ bWVkaWFfZW50aXR5X2NsZWFudXAoJnNkLT5lbnRpdHkpOw0KPiA+ICsJdjRsMl9jdHJsX2hhbmRs ZXJfZnJlZShzZC0+Y3RybF9oYW5kbGVyKTsNCj4gPiArCXBtX3J1bnRpbWVfZGlzYWJsZSgmY2xp ZW50LT5kZXYpOw0KPiA+ICsJaWYgKCFwbV9ydW50aW1lX3N0YXR1c19zdXNwZW5kZWQoJmNsaWVu dC0+ZGV2KSkNCj4gPiArCQlvdjAyYTEwX3Bvd2VyX29mZigmY2xpZW50LT5kZXYpOw0KPiA+ICsJ cG1fcnVudGltZV9zZXRfc3VzcGVuZGVkKCZjbGllbnQtPmRldik7DQo+ID4gKwltdXRleF9kZXN0 cm95KCZvdjAyYTEwLT5tdXRleCk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4g PiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIG92MDJhMTBfb2ZfbWF0 Y2hbXSA9IHsNCj4gPiArCXsgLmNvbXBhdGlibGUgPSAib3Z0aSxvdjAyYTEwIiB9LA0KPiA+ICsJ e30NCj4gPiArfTsNCj4gPiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgb3YwMmExMF9vZl9tYXRj aCk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IGkyY19kcml2ZXIgb3YwMmExMF9pMmNfZHJp dmVyID0gew0KPiA+ICsJLmRyaXZlciA9IHsNCj4gPiArCQkubmFtZSA9ICJvdjAyYTEwIiwNCj4g PiArCQkucG0gPSAmb3YwMmExMF9wbV9vcHMsDQo+ID4gKwkJLm9mX21hdGNoX3RhYmxlID0gb3Yw MmExMF9vZl9tYXRjaCwNCj4gPiArCX0sDQo+ID4gKwkucHJvYmVfbmV3CT0gJm92MDJhMTBfcHJv YmUsDQo+ID4gKwkucmVtb3ZlCQk9ICZvdjAyYTEwX3JlbW92ZSwNCj4gPiArfTsNCj4gDQo+ID4g Kw0KPiANCj4gUmVkdW5kYW50IGJsYW5rIGxpbmUuDQo+IA0KDQpGaXhlZCBpbiBuZXh0IHJlbGVh c2UuDQoNCj4gPiArbW9kdWxlX2kyY19kcml2ZXIob3YwMmExMF9pMmNfZHJpdmVyKTsNCj4gPiAr DQo+ID4gK01PRFVMRV9BVVRIT1IoIkRvbmdjaHVuIFpodSA8ZG9uZ2NodW4uemh1QG1lZGlhdGVr LmNvbT4iKTsNCj4gPiArTU9EVUxFX0RFU0NSSVBUSU9OKCJPbW5pVmlzaW9uIE9WMDJBMTAgc2Vu c29yIGRyaXZlciIpOw0KPiA+ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7DQo+ID4gLS0gDQo+ ID4gMi45LjINCj4gDQoNCg== From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY,URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4CA5CC2D0A7 for ; Fri, 4 Sep 2020 13:35:07 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A664F2100A for ; Fri, 4 Sep 2020 13:35:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="tACwLj97"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="E4HakSBM" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A664F2100A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=hffSmQ8AgnTf1RgwN6A/aUSiE2ADt6CdqhwozVEpy5E=; b=tACwLj97Nsi3mjCr/R3AKZv9J 7mcqBylTdm7N/WDJc599YaBB/9z2kTqMgPwweDjNu0nI21RQTHFomXzF+6jZPmTdKPZ5uAMpAd1uI sz11JGD7UoV5SW+iKzcCeM3uOq/fOstRm7nDpJ7tAexH+9KIJD4feSJO8aRLvMOH5QCUN6jZ9NU7d vrW+LCaHgfNTQnT8hD9aYus0i6ocKAFSAXMU1H+7KETHZnS3MWeH7KwxUAyg42eLPUriZq47yyjVz b/LGDgIGt7Bp1qgMzYkfIShp7A1E7/GGrqeC0+QvzFmNzHhBaTWCzFcKizB4uEL5ETSWCulHFFSDc NwI1ENbIw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEBrj-0003y5-Oz; Fri, 04 Sep 2020 13:34:55 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEBrW-0003st-Qj; Fri, 04 Sep 2020 13:34:53 +0000 X-UUID: 1b1ca3963173447485addcf128f824ad-20200904 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=22/iNI1bCMO52DJ7zmxWRbPYhTPUczPRCXOpoQjmtnA=; b=E4HakSBMiE1GEukUex9ubr50exHxNd6BfJWTTLJemmHVaA4co8VDATqO90CopiSx4sCLKD8TWPaX4+iirCQr05jmyF7vimsQbq/gu4PwmxyI/4noYS4Mf0/08Ic6pfLY7Usdw9yTCXkwJZLZYdO85b8tMO3r1nPlroKPSkZb7NY=; X-UUID: 1b1ca3963173447485addcf128f824ad-20200904 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 193557609; Fri, 04 Sep 2020 05:34:35 -0800 Received: from MTKMBS31N2.mediatek.inc (172.27.4.87) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 4 Sep 2020 06:24:32 -0700 Received: from MTKCAS32.mediatek.inc (172.27.4.184) by MTKMBS31N2.mediatek.inc (172.27.4.87) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 4 Sep 2020 21:24:28 +0800 Received: from [10.17.3.153] (10.17.3.153) by MTKCAS32.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 4 Sep 2020 21:24:26 +0800 Message-ID: <1599225767.4733.64.camel@mhfsdcap03> Subject: Re: [PATCH v14 2/2] media: i2c: Add OV02A10 image sensor driver From: Dongchun Zhu To: Andy Shevchenko Date: Fri, 4 Sep 2020 21:22:47 +0800 In-Reply-To: <20200902134421.GN1891694@smile.fi.intel.com> References: <20200902120122.24456-1-dongchun.zhu@mediatek.com> <20200902120122.24456-3-dongchun.zhu@mediatek.com> <20200902134421.GN1891694@smile.fi.intel.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: 7677D1418206308CDF70BED27549441915906F398580126A8871507F2954C0E12000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200904_093443_356350_591AB8DE X-CRM114-Status: GOOD ( 31.15 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, drinkcat@chromium.org, srv_heupstream@mediatek.com, shengnan.wang@mediatek.com, tfiga@chromium.org, louis.kuo@mediatek.com, sj.huang@mediatek.com, robh+dt@kernel.org, linux-mediatek@lists.infradead.org, dongchun.zhu@mediatek.com, sakari.ailus@linux.intel.com, matthias.bgg@gmail.com, bingbu.cao@intel.com, matrix.zhu@aliyun.com, mchehab@kernel.org, linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Hello Andy, Thanks for the review. On Wed, 2020-09-02 at 16:44 +0300, Andy Shevchenko wrote: > On Wed, Sep 02, 2020 at 08:01:22PM +0800, Dongchun Zhu wrote: > > Add a V4L2 sub-device driver for OmniVision OV02A10 image sensor. > > > > Some nit-picks below, after addressing, FWIW, > Reviewed-by: Andy Shevchenko > > > Signed-off-by: Dongchun Zhu > > --- > > MAINTAINERS | 1 + > > drivers/media/i2c/Kconfig | 13 + > > drivers/media/i2c/Makefile | 1 + > > drivers/media/i2c/ov02a10.c | 1083 +++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 1098 insertions(+) > > create mode 100644 drivers/media/i2c/ov02a10.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 48aa7a7..ce7d8fa 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -12724,6 +12724,7 @@ L: linux-media@vger.kernel.org > > S: Maintained > > T: git git://linuxtv.org/media_tree.git > > F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml > > +F: drivers/media/i2c/ov02a10.c > > > > OMNIVISION OV13858 SENSOR DRIVER > > M: Sakari Ailus > > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig > > index 48ae60a..f458804 100644 > > --- a/drivers/media/i2c/Kconfig > > +++ b/drivers/media/i2c/Kconfig > > @@ -825,6 +825,19 @@ config VIDEO_IMX355 > > To compile this driver as a module, choose M here: the > > module will be called imx355. > > > > +config VIDEO_OV02A10 > > + tristate "OmniVision OV02A10 sensor support" > > > + depends on I2C && VIDEO_V4L2 > > Dunno if V4L2 modules allow COMPILE_TEST, but looking below, can we stick with one pattern like > depends on VIDEO_V4L2 && I2C > ? > > Or is it the opposite (de facto in use)? > It seems there is no uniform standard for the dependency sequence currently. > > + select MEDIA_CONTROLLER > > + select VIDEO_V4L2_SUBDEV_API > > + select V4L2_FWNODE > > + help > > + This is a Video4Linux2 sensor driver for the OmniVision > > + OV02A10 camera sensor. > > + > > + To compile this driver as a module, choose M here: the > > + module will be called ov02a10. > > + > > config VIDEO_OV2640 > > tristate "OmniVision OV2640 sensor support" > > depends on VIDEO_V4L2 && I2C > > diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile > > index f0a7747..dc27e14 100644 > > --- a/drivers/media/i2c/Makefile > > +++ b/drivers/media/i2c/Makefile > > @@ -64,6 +64,7 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o > > obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o > > obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o > > obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o > > +obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o > > obj-$(CONFIG_VIDEO_OV2640) += ov2640.o > > obj-$(CONFIG_VIDEO_OV2680) += ov2680.o > > obj-$(CONFIG_VIDEO_OV2685) += ov2685.o > > diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c > > new file mode 100644 > > index 0000000..1f8c525 > > --- /dev/null > > +++ b/drivers/media/i2c/ov02a10.c > > @@ -0,0 +1,1083 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +// Copyright (c) 2020 MediaTek Inc. > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define CHIP_ID 0x2509 > > +#define OV02A10_REG_CHIP_ID_H 0x02 > > +#define OV02A10_REG_CHIP_ID_L 0x03 > > + > > +/* Bit[1] vertical upside down */ > > +/* Bit[0] horizontal mirror */ > > +#define REG_MIRROR_FLIP_CONTROL 0x3f > > + > > +/* Orientation */ > > +#define REG_MIRROR_FLIP_ENABLE 0x03 > > + > > +/* Bit[2:0] MIPI transmission speed select */ > > +#define TX_SPEED_AREA_SEL 0xa1 > > +#define OV02A10_MIPI_TX_SPEED_DEFAULT 0x04 > > + > > +#define REG_PAGE_SWITCH 0xfd > > +#define REG_GLOBAL_EFFECTIVE 0x01 > > +#define REG_ENABLE BIT(0) > > + > > +#define REG_SC_CTRL_MODE 0xac > > +#define SC_CTRL_MODE_STANDBY 0x00 > > +#define SC_CTRL_MODE_STREAMING 0x01 > > + > > +#define OV02A10_EXP_SHIFT 8 > > +#define OV02A10_REG_EXPOSURE_H 0x03 > > +#define OV02A10_REG_EXPOSURE_L 0x04 > > +#define OV02A10_EXPOSURE_MIN 4 > > +#define OV02A10_EXPOSURE_MAX_MARGIN 4 > > +#define OV02A10_EXPOSURE_STEP 1 > > + > > +#define OV02A10_VTS_SHIFT 8 > > +#define OV02A10_REG_VTS_H 0x05 > > +#define OV02A10_REG_VTS_L 0x06 > > > +#define OV02A10_VTS_MAX 0x209f > > Hex? (1) > > > +#define OV02A10_BASIC_LINE 1224 > > Decimal? (2) > > > + > > +#define OV02A10_REG_GAIN 0x24 > > > +#define OV02A10_GAIN_MIN 0x10 > > +#define OV02A10_GAIN_MAX 0xf8 > > +#define OV02A10_GAIN_STEP 0x01 > > +#define OV02A10_GAIN_DEFAULT 0x40 > > Not sure why these are in hex, but okay. Probably a reason behind (1) and (2) > as well. > >From my perspective, OV02A10_BASIC_LINE is defined from the aspect of 'u32 height' in 'struct ov02a10_mode'; while the others are related with sensor specific control registers, like VTS, GAIN, EXPSOURE... > > +/* Test pattern control */ > > +#define OV02A10_REG_TEST_PATTERN 0xb6 > > I'm wondering if you can rearrange registers that they will be sorted by value. > They are supposed to be classified by category. > > +#define HZ_PER_MHZ 1000000L > > +#define OV02A10_LINK_FREQ_390MHZ (390 * HZ_PER_MHZ) > > +#define OV02A10_ECLK_FREQ (24 * HZ_PER_MHZ) > > +#define OV02A10_DATA_LANES 1 > > +#define OV02A10_BITS_PER_SAMPLE 10 > > + > > +static const char * const ov02a10_supply_names[] = { > > + "dovdd", /* Digital I/O power */ > > + "avdd", /* Analog power */ > > + "dvdd", /* Digital core power */ > > +}; > > + > > +struct ov02a10_reg { > > + u8 addr; > > + u8 val; > > +}; > > + > > +struct ov02a10_reg_list { > > + u32 num_of_regs; > > + const struct ov02a10_reg *regs; > > +}; > > + > > +struct ov02a10_mode { > > + u32 width; > > + u32 height; > > + u32 exp_def; > > + u32 hts_def; > > + u32 vts_def; > > + const struct ov02a10_reg_list reg_list; > > +}; > > + > > +struct ov02a10 { > > + u32 eclk_freq; > > + /* Indication of MIPI transmission speed select */ > > + u32 mipi_clock_voltage; > > + /* Index of link frequency config to be used */ > > + u32 freq_index; > > + > > + struct clk *eclk; > > + struct gpio_desc *pd_gpio; > > + struct gpio_desc *rst_gpio; > > + struct regulator_bulk_data supplies[ARRAY_SIZE(ov02a10_supply_names)]; > > + > > + bool streaming; > > + bool upside_down; > > + > > + /* > > + * Serialize control access, get/set format, get selection > > + * and start streaming. > > + */ > > + struct mutex mutex; > > + struct v4l2_subdev subdev; > > + struct media_pad pad; > > + struct v4l2_mbus_framefmt fmt; > > + struct v4l2_ctrl_handler ctrl_handler; > > + struct v4l2_ctrl *exposure; > > + > > + const struct ov02a10_mode *cur_mode; > > +}; > > + > > +static inline struct ov02a10 *to_ov02a10(struct v4l2_subdev *sd) > > +{ > > + return container_of(sd, struct ov02a10, subdev); > > +} > > + > > +/* > > + * eclk 24Mhz > > + * pclk 39Mhz > > + * linelength 934(0x3a6) > > + * framelength 1390(0x56E) > > + * grabwindow_width 1600 > > + * grabwindow_height 1200 > > + * max_framerate 30fps > > + * mipi_datarate per lane 780Mbps > > + */ > > +static const struct ov02a10_reg ov02a10_1600x1200_regs[] = { > > + {0xfd, 0x01}, > > + {0xac, 0x00}, > > + {0xfd, 0x00}, > > + {0x2f, 0x29}, > > + {0x34, 0x00}, > > + {0x35, 0x21}, > > + {0x30, 0x15}, > > + {0x33, 0x01}, > > + {0xfd, 0x01}, > > + {0x44, 0x00}, > > + {0x2a, 0x4c}, > > + {0x2b, 0x1e}, > > + {0x2c, 0x60}, > > + {0x25, 0x11}, > > + {0x03, 0x01}, > > + {0x04, 0xae}, > > + {0x09, 0x00}, > > + {0x0a, 0x02}, > > + {0x06, 0xa6}, > > + {0x31, 0x00}, > > + {0x24, 0x40}, > > + {0x01, 0x01}, > > + {0xfb, 0x73}, > > + {0xfd, 0x01}, > > + {0x16, 0x04}, > > + {0x1c, 0x09}, > > + {0x21, 0x42}, > > + {0x12, 0x04}, > > + {0x13, 0x10}, > > + {0x11, 0x40}, > > + {0x33, 0x81}, > > + {0xd0, 0x00}, > > + {0xd1, 0x01}, > > + {0xd2, 0x00}, > > + {0x50, 0x10}, > > + {0x51, 0x23}, > > + {0x52, 0x20}, > > + {0x53, 0x10}, > > + {0x54, 0x02}, > > + {0x55, 0x20}, > > + {0x56, 0x02}, > > + {0x58, 0x48}, > > + {0x5d, 0x15}, > > + {0x5e, 0x05}, > > + {0x66, 0x66}, > > + {0x68, 0x68}, > > + {0x6b, 0x00}, > > + {0x6c, 0x00}, > > + {0x6f, 0x40}, > > + {0x70, 0x40}, > > + {0x71, 0x0a}, > > + {0x72, 0xf0}, > > + {0x73, 0x10}, > > + {0x75, 0x80}, > > + {0x76, 0x10}, > > + {0x84, 0x00}, > > + {0x85, 0x10}, > > + {0x86, 0x10}, > > + {0x87, 0x00}, > > + {0x8a, 0x22}, > > + {0x8b, 0x22}, > > + {0x19, 0xf1}, > > + {0x29, 0x01}, > > + {0xfd, 0x01}, > > + {0x9d, 0x16}, > > + {0xa0, 0x29}, > > + {0xa1, 0x04}, > > + {0xad, 0x62}, > > + {0xae, 0x00}, > > + {0xaf, 0x85}, > > + {0xb1, 0x01}, > > + {0x8e, 0x06}, > > + {0x8f, 0x40}, > > + {0x90, 0x04}, > > + {0x91, 0xb0}, > > + {0x45, 0x01}, > > + {0x46, 0x00}, > > + {0x47, 0x6c}, > > + {0x48, 0x03}, > > + {0x49, 0x8b}, > > + {0x4a, 0x00}, > > + {0x4b, 0x07}, > > + {0x4c, 0x04}, > > + {0x4d, 0xb7}, > > + {0xf0, 0x40}, > > + {0xf1, 0x40}, > > + {0xf2, 0x40}, > > + {0xf3, 0x40}, > > + {0x3f, 0x00}, > > + {0xfd, 0x01}, > > + {0x05, 0x00}, > > + {0x06, 0xa6}, > > + {0xfd, 0x01}, > > +}; > > + > > +static const char * const ov02a10_test_pattern_menu[] = { > > + "Disabled", > > + "Eight Vertical Colour Bars", > > +}; > > + > > +static const s64 link_freq_menu_items[] = { > > + OV02A10_LINK_FREQ_390MHZ, > > +}; > > + > > +static u64 to_pixel_rate(u32 f_index) > > +{ > > + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV02A10_DATA_LANES; > > + > > + do_div(pixel_rate, OV02A10_BITS_PER_SAMPLE); > > + > > + return pixel_rate; > > +} > > + > > +static const struct ov02a10_mode supported_modes[] = { > > + { > > + .width = 1600, > > + .height = 1200, > > + .exp_def = 0x01ae, > > + .hts_def = 0x03a6, > > + .vts_def = 0x056e, > > + .reg_list = { > > + .num_of_regs = ARRAY_SIZE(ov02a10_1600x1200_regs), > > + .regs = ov02a10_1600x1200_regs, > > + }, > > + }, > > +}; > > + > > +static int ov02a10_write_array(struct ov02a10 *ov02a10, > > + const struct ov02a10_reg_list *r_list) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + unsigned int i; > > + int ret; > > + > > + for (i = 0; i < r_list->num_of_regs; i++) { > > + ret = i2c_smbus_write_byte_data(client, r_list->regs[i].addr, > > + r_list->regs[i].val); > > + if (ret < 0) > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > +static int ov02a10_read_smbus(struct ov02a10 *ov02a10, unsigned char reg, > > + unsigned char *val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_read_byte_data(client, reg); > > + if (ret < 0) > > + return ret; > > + > > + *val = (unsigned char)ret; > > No sure why you have casting and why returned value is not u8. > Fine. 'unsigned char' would be replaced of 'u8' in next release. > > + return 0; > > +} > > + > > +static void ov02a10_fill_fmt(const struct ov02a10_mode *mode, > > + struct v4l2_mbus_framefmt *fmt) > > +{ > > + fmt->width = mode->width; > > + fmt->height = mode->height; > > + fmt->field = V4L2_FIELD_NONE; > > +} > > + > > +static int ov02a10_set_fmt(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_format *fmt) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; > > + struct v4l2_mbus_framefmt *frame_fmt; > > + int ret = 0; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (ov02a10->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { > > + ret = -EBUSY; > > + goto error; > > + } > > + > > + /* Only one sensor mode supported */ > > + mbus_fmt->code = ov02a10->fmt.code; > > + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); > > + > > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) > > + frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); > > + else > > + frame_fmt = &ov02a10->fmt; > > + > > + *frame_fmt = *mbus_fmt; > > + > > +error: > > Like in other places be more precise > > out_unlock: > Sounds good naming. Fixed in next release. > > + mutex_unlock(&ov02a10->mutex); > > + return ret; > > +} > > + > > +static int ov02a10_get_fmt(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_format *fmt) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > > + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); > > + } else { > > + fmt->format = ov02a10->fmt; > > + mbus_fmt->code = ov02a10->fmt.code; > > + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); > > + } > > + > > + mutex_unlock(&ov02a10->mutex); > > + > > + return 0; > > +} > > + > > +static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_mbus_code_enum *code) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + if (code->index != 0) > > + return -EINVAL; > > + > > + code->code = ov02a10->fmt.code; > > + > > + return 0; > > +} > > + > > +static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_frame_size_enum *fse) > > +{ > > + if (fse->index >= ARRAY_SIZE(supported_modes)) > > + return -EINVAL; > > + > > + fse->min_width = supported_modes[fse->index].width; > > + fse->max_width = supported_modes[fse->index].width; > > + fse->max_height = supported_modes[fse->index].height; > > + fse->min_height = supported_modes[fse->index].height; > > + > > + return 0; > > +} > > + > > +static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + u16 id; > > + u8 chip_id_h; > > + u8 chip_id_l; > > + int ret; > > + > > + /* Check sensor revision */ > > + ret = ov02a10_read_smbus(ov02a10, OV02A10_REG_CHIP_ID_H, &chip_id_h); > > + if (ret) > > + return ret; > > + > > + ret = ov02a10_read_smbus(ov02a10, OV02A10_REG_CHIP_ID_L, &chip_id_l); > > + if (ret) > > + return ret; > > I'm wondering if above can be done in one bulk transfer (reading 16-bit value). > > > + id = (chip_id_h << 8) | chip_id_l; > > If above can be achieved, this one should be rather something like > le16_to_cpu() (or be16) with corresponding type of chip_id. > Yes. i2c_smbus_read_word_data() functions could read both registers in using a single i2c transaction. Let me try locally first. > > + if (id != CHIP_ID) { > > + dev_err(&client->dev, "Unexpected sensor id(%04x)\n", id); > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int ov02a10_power_on(struct device *dev) > > +{ > > > + struct i2c_client *client = to_i2c_client(dev); > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > struct v4l2_subdev *sd = dev_get_drvdata(dev); > > Same for the rest similar cases. > We've discussed the issue in DW9768 V2. For V4L2 sub-device drivers, dev_get_drvdata() shouldn't be used directly. More details please check the Google Issue: https://partnerissuetracker.corp.google.com/issues/147957975 > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + int ret; > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); > > + > > + ret = clk_prepare_enable(ov02a10->eclk); > > + if (ret < 0) { > > + dev_err(dev, "failed to enable eclk\n"); > > + return ret; > > + } > > + > > + ret = regulator_bulk_enable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + if (ret < 0) { > > + dev_err(dev, "failed to enable regulators\n"); > > + goto disable_clk; > > + } > > + usleep_range(5000, 6000); > > + > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 0); > > + usleep_range(5000, 6000); > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 0); > > + usleep_range(5000, 6000); > > + > > + ret = ov02a10_check_sensor_id(ov02a10); > > + if (ret) > > + goto disable_regulator; > > + > > + return 0; > > + > > +disable_regulator: > > + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > +disable_clk: > > + clk_disable_unprepare(ov02a10->eclk); > > + > > + return ret; > > +} > > + > > +static int ov02a10_power_off(struct device *dev) > > +{ > > + struct i2c_client *client = to_i2c_client(dev); > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); > > + clk_disable_unprepare(ov02a10->eclk); > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); > > + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + > > + return 0; > > +} > > + > > +static int __ov02a10_start_stream(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + const struct ov02a10_reg_list *reg_list; > > + int ret; > > + > > + /* Apply default values of current mode */ > > + reg_list = &ov02a10->cur_mode->reg_list; > > + ret = ov02a10_write_array(ov02a10, reg_list); > > + if (ret) > > + return ret; > > + > > + /* Apply customized values from user */ > > + ret = __v4l2_ctrl_handler_setup(ov02a10->subdev.ctrl_handler); > > + if (ret) > > + return ret; > > + > > + /* Set orientation to 180 degree */ > > + if (ov02a10->upside_down) { > > + ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, > > + REG_MIRROR_FLIP_ENABLE); > > + if (ret) { > > + dev_err(&client->dev, "failed to set orientation\n"); > > + return ret; > > + } > > + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + } > > + > > + /* Set MIPI TX speed according to DT property */ > > + if (ov02a10->mipi_clock_voltage != OV02A10_MIPI_TX_SPEED_DEFAULT) { > > + ret = i2c_smbus_write_byte_data(client, TX_SPEED_AREA_SEL, > > + ov02a10->mipi_clock_voltage); > > + if (ret < 0) > > + return ret; > > + } > > + > > + /* Set stream on register */ > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STREAMING); > > +} > > + > > +static int __ov02a10_stop_stream(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STANDBY); > > +} > > + > > +static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg) > > +{ > > + struct v4l2_subdev_format fmt = { > > + .which = V4L2_SUBDEV_FORMAT_TRY, > > + .format = { > > + .width = 1600, > > + .height = 1200, > > + } > > + }; > > + > > + ov02a10_set_fmt(sd, cfg, &fmt); > > + > > + return 0; > > +} > > + > > +static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (ov02a10->streaming == on) > > + goto unlock_and_return; > > + > > + if (on) { > > + ret = pm_runtime_get_sync(&client->dev); > > + if (ret < 0) { > > + pm_runtime_put_noidle(&client->dev); > > + goto unlock_and_return; > > + } > > + > > + ret = __ov02a10_start_stream(ov02a10); > > + if (ret) { > > + __ov02a10_stop_stream(ov02a10); > > + ov02a10->streaming = !on; > > + goto err_rpm_put; > > + } > > + } else { > > + __ov02a10_stop_stream(ov02a10); > > + pm_runtime_put(&client->dev); > > + } > > + > > + ov02a10->streaming = on; > > + mutex_unlock(&ov02a10->mutex); > > + > > + return 0; > > + > > +err_rpm_put: > > + pm_runtime_put(&client->dev); > > +unlock_and_return: > > + mutex_unlock(&ov02a10->mutex); > > + > > + return ret; > > +} > > + > > +static const struct dev_pm_ops ov02a10_pm_ops = { > > + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > > + pm_runtime_force_resume) > > + SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) > > +}; > > + > > +/* > > + * ov02a10_set_exposure - Function called when setting exposure time > > + * @priv: Pointer to device structure > > + * @val: Variable for exposure time, in the unit of micro-second > > + * > > + * Set exposure time based on input value. > > + * > > + * Return: 0 on success > > + */ > > +static int ov02a10_set_exposure(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_H, > > + val >> OV02A10_EXP_SHIFT); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_L, val); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_gain(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_GAIN, val); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_vblank(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + u32 vts = val + ov02a10->cur_mode->height - OV02A10_BASIC_LINE; > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_H, > > + vts >> OV02A10_VTS_SHIFT); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_L, vts); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_test_pattern(struct ov02a10 *ov02a10, int pattern) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_TEST_PATTERN, > > + pattern); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STREAMING); > > +} > > + > > +static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) > > +{ > > + struct ov02a10 *ov02a10 = container_of(ctrl->handler, > > + struct ov02a10, ctrl_handler); > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + s64 max_expo; > > + int ret; > > + > > + /* Propagate change of current control to all related controls */ > > + if (ctrl->id == V4L2_CID_VBLANK) { > > + /* Update max exposure while meeting expected vblanking */ > > + max_expo = ov02a10->cur_mode->height + ctrl->val - > > + OV02A10_EXPOSURE_MAX_MARGIN; > > + __v4l2_ctrl_modify_range(ov02a10->exposure, > > + ov02a10->exposure->minimum, max_expo, > > + ov02a10->exposure->step, > > + ov02a10->exposure->default_value); > > + } > > + > > + /* V4L2 controls values will be applied only when power is already up */ > > + if (!pm_runtime_get_if_in_use(&client->dev)) > > + return 0; > > + > > + switch (ctrl->id) { > > + case V4L2_CID_EXPOSURE: > > + ret = ov02a10_set_exposure(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_ANALOGUE_GAIN: > > + ret = ov02a10_set_gain(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_VBLANK: > > + ret = ov02a10_set_vblank(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_TEST_PATTERN: > > + ret = ov02a10_set_test_pattern(ov02a10, ctrl->val); > > + break; > > + default: > > + ret = -EINVAL; > > + break; > > + }; > > + > > + pm_runtime_put(&client->dev); > > + > > + return ret; > > +} > > + > > +static const struct v4l2_subdev_video_ops ov02a10_video_ops = { > > + .s_stream = ov02a10_s_stream, > > +}; > > + > > +static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = { > > + .init_cfg = ov02a10_entity_init_cfg, > > + .enum_mbus_code = ov02a10_enum_mbus_code, > > + .enum_frame_size = ov02a10_enum_frame_sizes, > > + .get_fmt = ov02a10_get_fmt, > > + .set_fmt = ov02a10_set_fmt, > > +}; > > + > > +static const struct v4l2_subdev_ops ov02a10_subdev_ops = { > > + .video = &ov02a10_video_ops, > > + .pad = &ov02a10_pad_ops, > > +}; > > + > > +static const struct media_entity_operations ov02a10_subdev_entity_ops = { > > + .link_validate = v4l2_subdev_link_validate, > > +}; > > + > > +static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { > > + .s_ctrl = ov02a10_set_ctrl, > > +}; > > + > > +static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + const struct ov02a10_mode *mode; > > + struct v4l2_ctrl_handler *handler; > > + struct v4l2_ctrl *ctrl; > > + s64 exposure_max; > > + s64 vblank_def; > > + s64 pixel_rate; > > + s64 h_blank; > > + int ret; > > + > > + handler = &ov02a10->ctrl_handler; > > + mode = ov02a10->cur_mode; > > + ret = v4l2_ctrl_handler_init(handler, 7); > > + if (ret) > > + return ret; > > + > > + handler->lock = &ov02a10->mutex; > > + > > + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, > > + link_freq_menu_items); > > + if (ctrl) > > + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > + > > + pixel_rate = to_pixel_rate(0); > > + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, > > + pixel_rate); > > + > > + h_blank = mode->hts_def - mode->width; > > + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, > > + h_blank); > > + > > + vblank_def = mode->vts_def - mode->height; > > + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, V4L2_CID_VBLANK, > > + vblank_def, OV02A10_VTS_MAX - mode->height, 1, > > + vblank_def); > > + > > + exposure_max = mode->vts_def - 4; > > + ov02a10->exposure = v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_EXPOSURE, > > + OV02A10_EXPOSURE_MIN, > > + exposure_max, > > + OV02A10_EXPOSURE_STEP, > > + mode->exp_def); > > + > > + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_ANALOGUE_GAIN, OV02A10_GAIN_MIN, > > + OV02A10_GAIN_MAX, OV02A10_GAIN_STEP, > > + OV02A10_GAIN_DEFAULT); > > + > > + v4l2_ctrl_new_std_menu_items(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_TEST_PATTERN, > > + ARRAY_SIZE(ov02a10_test_pattern_menu) - 1, > > + 0, 0, ov02a10_test_pattern_menu); > > + > > + if (handler->error) { > > + ret = handler->error; > > + dev_err(&client->dev, "failed to init controls(%d)\n", ret); > > + goto err_free_handler; > > + } > > + > > + ov02a10->subdev.ctrl_handler = handler; > > + > > + return 0; > > + > > +err_free_handler: > > + v4l2_ctrl_handler_free(handler); > > + > > + return ret; > > +} > > + > > +static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) > > +{ > > + struct fwnode_handle *ep; > > + struct fwnode_handle *fwnode = dev_fwnode(dev); > > + struct v4l2_fwnode_endpoint bus_cfg = { > > + .bus_type = V4L2_MBUS_CSI2_DPHY, > > + }; > > + unsigned int i, j; > > + int ret; > > + > > + if (!fwnode) > > + return -EINVAL; > > + > > + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); > > + if (!ep) > > + return -ENXIO; > > + > > + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); > > + fwnode_handle_put(ep); > > + if (ret) > > + return ret; > > + > > + if (!bus_cfg.nr_of_link_frequencies) { > > + dev_err(dev, "no link frequencies defined\n"); > > + ret = -EINVAL; > > + goto check_hwcfg_error; > > + } > > If it's 0, the below will break on 'if (j == 0)' with slightly different but > informative enough message. What do you keep above check for? > I still prefer to the original version. If 'bus_cfg.nr_of_link_frequencies' is 0, shouldn't we directly return error? > > + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { > > + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { > > + if (link_freq_menu_items[i] == > > + bus_cfg.link_frequencies[j]) { > > + ov02a10->freq_index = i; > > + break; > > + } > > + } > > + > > + if (j == bus_cfg.nr_of_link_frequencies) { > > + dev_err(dev, "no link frequency %lld supported\n", > > + link_freq_menu_items[i]); > > + ret = -EINVAL; > > > + goto check_hwcfg_error; > > 'break;' won't work? > > > + } > > + } > > + > > +check_hwcfg_error: > > out_endpoint_free: > It seems that OV8856 keeps the same pattern. > > + v4l2_fwnode_endpoint_free(&bus_cfg); > > + > > + return ret; > > +} > > + > > +static int ov02a10_probe(struct i2c_client *client) > > +{ > > + struct device *dev = &client->dev; > > + struct ov02a10 *ov02a10; > > + unsigned int rotation; > > + unsigned int cnt = 0; > > + unsigned int i; > > > + unsigned int num_freq_clk_volt = 2 * ARRAY_SIZE(link_freq_menu_items); > > Can it be moved upper to improve readability? > Fixed in next release. > > + int ret; > > + > > + ov02a10 = devm_kzalloc(dev, sizeof(*ov02a10), GFP_KERNEL); > > + if (!ov02a10) > > + return -ENOMEM; > > + > > + ret = ov02a10_check_hwcfg(dev, ov02a10); > > + if (ret) { > > + dev_err(dev, "failed to check HW configuration: %d\n", ret); > > + return ret; > > + } > > + > > + v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops); > > + ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT; > > + ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; > > + > > + /* Optional indication of physical rotation of sensor */ > > + ret = fwnode_property_read_u32(dev_fwnode(dev), "rotation", &rotation); > > + if (!ret && rotation == 180) { > > Can be simplified (but I'm fine with above): > > unsigned int rotation = 0; > ... > fwnode_property_read_u32(..., &rotation); > if (rotation == 180) { > ... > } > Sounds like the readability is improved using the latter style :-) > > + ov02a10->upside_down = true; > > + ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; > > + } > > + > > + /* Optional indication of MIPI clock voltage unit */ > > + ret = fwnode_property_read_u32_array(dev_fwnode(dev), > > + "ovti,mipi-clock-voltage", NULL, > > + 0); > > ret = fwnode_property_count_u32(...); // will be one line > Great APIs! > > + if (ret > 0 && ret % 2 == 0) { > > + u32 freq_clk_volt[ret]; > > + > > + fwnode_property_read_u32_array(dev_fwnode(dev), > > + "ovti,mipi-clock-voltage", > > + freq_clk_volt, > > + ARRAY_SIZE(freq_clk_volt)); > > + > > + while (num_freq_clk_volt) { > > + unsigned long freq; > > + unsigned long volt; > > + > > + if (cnt >= ARRAY_SIZE(freq_clk_volt)) { > > + dev_warn(dev, "mismatched link frequency\n"); > > + break; > > + } > > + > > > + freq = freq_clk_volt[cnt++] * 1000; > > HZ_PER_KHZ? > Fixed in next release. > > + volt = freq_clk_volt[cnt++]; > > + > > + /* Get clock voltage unit value from DT */ > > + if (freq == link_freq_menu_items[ov02a10->freq_index]) { > > + ov02a10->mipi_clock_voltage = volt; > > + break; > > + } > > + > > + num_freq_clk_volt -= 2; > > + } > > + } > > + > > + /* Get external input clock (eclk) */ > > + ov02a10->eclk = devm_clk_get(dev, "eclk"); > > + if (IS_ERR(ov02a10->eclk)) { > > + ret = PTR_ERR(ov02a10->eclk); > > + dev_err(dev, "failed to get eclk %d\n", ret); > > + return ret; > > return dev_err_probe(...); > Great APIs... > > + } > > + > > + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", > > + &ov02a10->eclk_freq); > > + if (ret) { > > + dev_err(dev, "failed to get eclk frequency\n"); > > + return ret; > > + } > > > + ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); > > + if (ret) { > > + dev_err(dev, "failed to set eclk frequency (24MHz)\n"); > > + return ret; > > + } > > + > > + if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) { > > + dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); > > + return -EINVAL; > > + } > > + > > + ov02a10->pd_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); > > + if (IS_ERR(ov02a10->pd_gpio)) { > > > + ret = PTR_ERR(ov02a10->pd_gpio); > > + dev_err(dev, "failed to get powerdown-gpios %d\n", ret); > > + return ret; > > return dev_err_probe(...); > It would be simplified using dev_err_probe directly in next release. > > + } > > + > > + ov02a10->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); > > + if (IS_ERR(ov02a10->rst_gpio)) { > > + ret = PTR_ERR(ov02a10->rst_gpio); > > + dev_err(dev, "failed to get reset-gpios %d\n", ret); > > + return ret; > > Ditto. > Fixed in next release. > > + } > > + > > + for (i = 0; i < ARRAY_SIZE(ov02a10_supply_names); i++) > > + ov02a10->supplies[i].supply = ov02a10_supply_names[i]; > > + > > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + if (ret) { > > > + dev_err(dev, "failed to get regulators\n"); > > + return ret; > > Ditto. > Fixed in next release. > > + } > > + > > + mutex_init(&ov02a10->mutex); > > + ov02a10->cur_mode = &supported_modes[0]; > > + > > + ret = ov02a10_initialize_controls(ov02a10); > > + if (ret) { > > + dev_err(dev, "failed to initialize controls\n"); > > + goto err_destroy_mutex; > > + } > > + > > + ov02a10->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; > > + ov02a10->subdev.entity.ops = &ov02a10_subdev_entity_ops; > > + ov02a10->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; > > + ov02a10->pad.flags = MEDIA_PAD_FL_SOURCE; > > + > > + ret = media_entity_pads_init(&ov02a10->subdev.entity, 1, &ov02a10->pad); > > + if (ret < 0) { > > + dev_err(dev, "failed to init entity pads: %d", ret); > > + goto err_free_handler; > > + } > > + > > + pm_runtime_enable(dev); > > + if (!pm_runtime_enabled(dev)) { > > + ret = ov02a10_power_on(dev); > > + if (ret < 0) { > > + dev_err(dev, "failed to power on: %d\n", ret); > > + goto err_clean_entity; > > + } > > + } > > + > > + ret = v4l2_async_register_subdev(&ov02a10->subdev); > > + if (ret) { > > + dev_err(dev, "failed to register V4L2 subdev: %d\n", ret); > > + goto err_power_off; > > + } > > + > > + return 0; > > + > > +err_power_off: > > + if (pm_runtime_enabled(dev)) > > + pm_runtime_disable(dev); > > + else > > + ov02a10_power_off(dev); > > +err_clean_entity: > > + media_entity_cleanup(&ov02a10->subdev.entity); > > +err_free_handler: > > + v4l2_ctrl_handler_free(ov02a10->subdev.ctrl_handler); > > +err_destroy_mutex: > > + mutex_destroy(&ov02a10->mutex); > > + > > + return ret; > > +} > > + > > +static int ov02a10_remove(struct i2c_client *client) > > +{ > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + v4l2_async_unregister_subdev(sd); > > + media_entity_cleanup(&sd->entity); > > + v4l2_ctrl_handler_free(sd->ctrl_handler); > > + pm_runtime_disable(&client->dev); > > + if (!pm_runtime_status_suspended(&client->dev)) > > + ov02a10_power_off(&client->dev); > > + pm_runtime_set_suspended(&client->dev); > > + mutex_destroy(&ov02a10->mutex); > > + > > + return 0; > > +} > > + > > +static const struct of_device_id ov02a10_of_match[] = { > > + { .compatible = "ovti,ov02a10" }, > > + {} > > +}; > > +MODULE_DEVICE_TABLE(of, ov02a10_of_match); > > + > > +static struct i2c_driver ov02a10_i2c_driver = { > > + .driver = { > > + .name = "ov02a10", > > + .pm = &ov02a10_pm_ops, > > + .of_match_table = ov02a10_of_match, > > + }, > > + .probe_new = &ov02a10_probe, > > + .remove = &ov02a10_remove, > > +}; > > > + > > Redundant blank line. > Fixed in next release. > > +module_i2c_driver(ov02a10_i2c_driver); > > + > > +MODULE_AUTHOR("Dongchun Zhu "); > > +MODULE_DESCRIPTION("OmniVision OV02A10 sensor driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.9.2 > _______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY,URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13D4CC43461 for ; Fri, 4 Sep 2020 13:36:49 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B1EAC2083B for ; Fri, 4 Sep 2020 13:36:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="ooDDPwty"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="E4HakSBM" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B1EAC2083B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=1dooxU1k717oYpcZPJCXcbD4GBYEOKE8iT/O0SkZ2rM=; b=ooDDPwtyWLrvUy3Gk2S6b+8OK 1RM+rS3RRAxCBMG0eugLOC0YrQuWVIKamQlhepGglYPPMKpseRk6YEf2DWPw/Quwoj3TCLsmcxRrQ exZ2VQqKAM7NjZVKISlCoc0wbRn4BxfdrAfTYqhEfke4YIYXwtKVUxXm/vzCRUUVq/cqc9mc1joh1 idYTN9mfBRDlf4JhbFOGvmy49k+Tfa+uctXwzvGKF9F8ObMvK3JwrqBOc/YSKxWEzsnC5Y+CY0KYK VInga8xkDkYoDfzMYBb9SyvPmmnLXkNjvavlYYxIBhdBM1/mEqVMAbF/S8p4UlPtmS/AseSjwJRD2 +omUctfDg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEBrl-0003yM-1v; Fri, 04 Sep 2020 13:34:57 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEBrW-0003st-Qj; Fri, 04 Sep 2020 13:34:53 +0000 X-UUID: 1b1ca3963173447485addcf128f824ad-20200904 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=22/iNI1bCMO52DJ7zmxWRbPYhTPUczPRCXOpoQjmtnA=; b=E4HakSBMiE1GEukUex9ubr50exHxNd6BfJWTTLJemmHVaA4co8VDATqO90CopiSx4sCLKD8TWPaX4+iirCQr05jmyF7vimsQbq/gu4PwmxyI/4noYS4Mf0/08Ic6pfLY7Usdw9yTCXkwJZLZYdO85b8tMO3r1nPlroKPSkZb7NY=; X-UUID: 1b1ca3963173447485addcf128f824ad-20200904 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 193557609; Fri, 04 Sep 2020 05:34:35 -0800 Received: from MTKMBS31N2.mediatek.inc (172.27.4.87) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 4 Sep 2020 06:24:32 -0700 Received: from MTKCAS32.mediatek.inc (172.27.4.184) by MTKMBS31N2.mediatek.inc (172.27.4.87) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 4 Sep 2020 21:24:28 +0800 Received: from [10.17.3.153] (10.17.3.153) by MTKCAS32.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 4 Sep 2020 21:24:26 +0800 Message-ID: <1599225767.4733.64.camel@mhfsdcap03> Subject: Re: [PATCH v14 2/2] media: i2c: Add OV02A10 image sensor driver From: Dongchun Zhu To: Andy Shevchenko Date: Fri, 4 Sep 2020 21:22:47 +0800 In-Reply-To: <20200902134421.GN1891694@smile.fi.intel.com> References: <20200902120122.24456-1-dongchun.zhu@mediatek.com> <20200902120122.24456-3-dongchun.zhu@mediatek.com> <20200902134421.GN1891694@smile.fi.intel.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: 7677D1418206308CDF70BED27549441915906F398580126A8871507F2954C0E12000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200904_093443_356350_591AB8DE X-CRM114-Status: GOOD ( 31.15 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, drinkcat@chromium.org, srv_heupstream@mediatek.com, shengnan.wang@mediatek.com, tfiga@chromium.org, louis.kuo@mediatek.com, sj.huang@mediatek.com, robh+dt@kernel.org, linux-mediatek@lists.infradead.org, dongchun.zhu@mediatek.com, sakari.ailus@linux.intel.com, matthias.bgg@gmail.com, bingbu.cao@intel.com, matrix.zhu@aliyun.com, mchehab@kernel.org, linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hello Andy, Thanks for the review. On Wed, 2020-09-02 at 16:44 +0300, Andy Shevchenko wrote: > On Wed, Sep 02, 2020 at 08:01:22PM +0800, Dongchun Zhu wrote: > > Add a V4L2 sub-device driver for OmniVision OV02A10 image sensor. > > > > Some nit-picks below, after addressing, FWIW, > Reviewed-by: Andy Shevchenko > > > Signed-off-by: Dongchun Zhu > > --- > > MAINTAINERS | 1 + > > drivers/media/i2c/Kconfig | 13 + > > drivers/media/i2c/Makefile | 1 + > > drivers/media/i2c/ov02a10.c | 1083 +++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 1098 insertions(+) > > create mode 100644 drivers/media/i2c/ov02a10.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 48aa7a7..ce7d8fa 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -12724,6 +12724,7 @@ L: linux-media@vger.kernel.org > > S: Maintained > > T: git git://linuxtv.org/media_tree.git > > F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml > > +F: drivers/media/i2c/ov02a10.c > > > > OMNIVISION OV13858 SENSOR DRIVER > > M: Sakari Ailus > > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig > > index 48ae60a..f458804 100644 > > --- a/drivers/media/i2c/Kconfig > > +++ b/drivers/media/i2c/Kconfig > > @@ -825,6 +825,19 @@ config VIDEO_IMX355 > > To compile this driver as a module, choose M here: the > > module will be called imx355. > > > > +config VIDEO_OV02A10 > > + tristate "OmniVision OV02A10 sensor support" > > > + depends on I2C && VIDEO_V4L2 > > Dunno if V4L2 modules allow COMPILE_TEST, but looking below, can we stick with one pattern like > depends on VIDEO_V4L2 && I2C > ? > > Or is it the opposite (de facto in use)? > It seems there is no uniform standard for the dependency sequence currently. > > + select MEDIA_CONTROLLER > > + select VIDEO_V4L2_SUBDEV_API > > + select V4L2_FWNODE > > + help > > + This is a Video4Linux2 sensor driver for the OmniVision > > + OV02A10 camera sensor. > > + > > + To compile this driver as a module, choose M here: the > > + module will be called ov02a10. > > + > > config VIDEO_OV2640 > > tristate "OmniVision OV2640 sensor support" > > depends on VIDEO_V4L2 && I2C > > diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile > > index f0a7747..dc27e14 100644 > > --- a/drivers/media/i2c/Makefile > > +++ b/drivers/media/i2c/Makefile > > @@ -64,6 +64,7 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o > > obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o > > obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o > > obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o > > +obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o > > obj-$(CONFIG_VIDEO_OV2640) += ov2640.o > > obj-$(CONFIG_VIDEO_OV2680) += ov2680.o > > obj-$(CONFIG_VIDEO_OV2685) += ov2685.o > > diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c > > new file mode 100644 > > index 0000000..1f8c525 > > --- /dev/null > > +++ b/drivers/media/i2c/ov02a10.c > > @@ -0,0 +1,1083 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +// Copyright (c) 2020 MediaTek Inc. > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define CHIP_ID 0x2509 > > +#define OV02A10_REG_CHIP_ID_H 0x02 > > +#define OV02A10_REG_CHIP_ID_L 0x03 > > + > > +/* Bit[1] vertical upside down */ > > +/* Bit[0] horizontal mirror */ > > +#define REG_MIRROR_FLIP_CONTROL 0x3f > > + > > +/* Orientation */ > > +#define REG_MIRROR_FLIP_ENABLE 0x03 > > + > > +/* Bit[2:0] MIPI transmission speed select */ > > +#define TX_SPEED_AREA_SEL 0xa1 > > +#define OV02A10_MIPI_TX_SPEED_DEFAULT 0x04 > > + > > +#define REG_PAGE_SWITCH 0xfd > > +#define REG_GLOBAL_EFFECTIVE 0x01 > > +#define REG_ENABLE BIT(0) > > + > > +#define REG_SC_CTRL_MODE 0xac > > +#define SC_CTRL_MODE_STANDBY 0x00 > > +#define SC_CTRL_MODE_STREAMING 0x01 > > + > > +#define OV02A10_EXP_SHIFT 8 > > +#define OV02A10_REG_EXPOSURE_H 0x03 > > +#define OV02A10_REG_EXPOSURE_L 0x04 > > +#define OV02A10_EXPOSURE_MIN 4 > > +#define OV02A10_EXPOSURE_MAX_MARGIN 4 > > +#define OV02A10_EXPOSURE_STEP 1 > > + > > +#define OV02A10_VTS_SHIFT 8 > > +#define OV02A10_REG_VTS_H 0x05 > > +#define OV02A10_REG_VTS_L 0x06 > > > +#define OV02A10_VTS_MAX 0x209f > > Hex? (1) > > > +#define OV02A10_BASIC_LINE 1224 > > Decimal? (2) > > > + > > +#define OV02A10_REG_GAIN 0x24 > > > +#define OV02A10_GAIN_MIN 0x10 > > +#define OV02A10_GAIN_MAX 0xf8 > > +#define OV02A10_GAIN_STEP 0x01 > > +#define OV02A10_GAIN_DEFAULT 0x40 > > Not sure why these are in hex, but okay. Probably a reason behind (1) and (2) > as well. > >From my perspective, OV02A10_BASIC_LINE is defined from the aspect of 'u32 height' in 'struct ov02a10_mode'; while the others are related with sensor specific control registers, like VTS, GAIN, EXPSOURE... > > +/* Test pattern control */ > > +#define OV02A10_REG_TEST_PATTERN 0xb6 > > I'm wondering if you can rearrange registers that they will be sorted by value. > They are supposed to be classified by category. > > +#define HZ_PER_MHZ 1000000L > > +#define OV02A10_LINK_FREQ_390MHZ (390 * HZ_PER_MHZ) > > +#define OV02A10_ECLK_FREQ (24 * HZ_PER_MHZ) > > +#define OV02A10_DATA_LANES 1 > > +#define OV02A10_BITS_PER_SAMPLE 10 > > + > > +static const char * const ov02a10_supply_names[] = { > > + "dovdd", /* Digital I/O power */ > > + "avdd", /* Analog power */ > > + "dvdd", /* Digital core power */ > > +}; > > + > > +struct ov02a10_reg { > > + u8 addr; > > + u8 val; > > +}; > > + > > +struct ov02a10_reg_list { > > + u32 num_of_regs; > > + const struct ov02a10_reg *regs; > > +}; > > + > > +struct ov02a10_mode { > > + u32 width; > > + u32 height; > > + u32 exp_def; > > + u32 hts_def; > > + u32 vts_def; > > + const struct ov02a10_reg_list reg_list; > > +}; > > + > > +struct ov02a10 { > > + u32 eclk_freq; > > + /* Indication of MIPI transmission speed select */ > > + u32 mipi_clock_voltage; > > + /* Index of link frequency config to be used */ > > + u32 freq_index; > > + > > + struct clk *eclk; > > + struct gpio_desc *pd_gpio; > > + struct gpio_desc *rst_gpio; > > + struct regulator_bulk_data supplies[ARRAY_SIZE(ov02a10_supply_names)]; > > + > > + bool streaming; > > + bool upside_down; > > + > > + /* > > + * Serialize control access, get/set format, get selection > > + * and start streaming. > > + */ > > + struct mutex mutex; > > + struct v4l2_subdev subdev; > > + struct media_pad pad; > > + struct v4l2_mbus_framefmt fmt; > > + struct v4l2_ctrl_handler ctrl_handler; > > + struct v4l2_ctrl *exposure; > > + > > + const struct ov02a10_mode *cur_mode; > > +}; > > + > > +static inline struct ov02a10 *to_ov02a10(struct v4l2_subdev *sd) > > +{ > > + return container_of(sd, struct ov02a10, subdev); > > +} > > + > > +/* > > + * eclk 24Mhz > > + * pclk 39Mhz > > + * linelength 934(0x3a6) > > + * framelength 1390(0x56E) > > + * grabwindow_width 1600 > > + * grabwindow_height 1200 > > + * max_framerate 30fps > > + * mipi_datarate per lane 780Mbps > > + */ > > +static const struct ov02a10_reg ov02a10_1600x1200_regs[] = { > > + {0xfd, 0x01}, > > + {0xac, 0x00}, > > + {0xfd, 0x00}, > > + {0x2f, 0x29}, > > + {0x34, 0x00}, > > + {0x35, 0x21}, > > + {0x30, 0x15}, > > + {0x33, 0x01}, > > + {0xfd, 0x01}, > > + {0x44, 0x00}, > > + {0x2a, 0x4c}, > > + {0x2b, 0x1e}, > > + {0x2c, 0x60}, > > + {0x25, 0x11}, > > + {0x03, 0x01}, > > + {0x04, 0xae}, > > + {0x09, 0x00}, > > + {0x0a, 0x02}, > > + {0x06, 0xa6}, > > + {0x31, 0x00}, > > + {0x24, 0x40}, > > + {0x01, 0x01}, > > + {0xfb, 0x73}, > > + {0xfd, 0x01}, > > + {0x16, 0x04}, > > + {0x1c, 0x09}, > > + {0x21, 0x42}, > > + {0x12, 0x04}, > > + {0x13, 0x10}, > > + {0x11, 0x40}, > > + {0x33, 0x81}, > > + {0xd0, 0x00}, > > + {0xd1, 0x01}, > > + {0xd2, 0x00}, > > + {0x50, 0x10}, > > + {0x51, 0x23}, > > + {0x52, 0x20}, > > + {0x53, 0x10}, > > + {0x54, 0x02}, > > + {0x55, 0x20}, > > + {0x56, 0x02}, > > + {0x58, 0x48}, > > + {0x5d, 0x15}, > > + {0x5e, 0x05}, > > + {0x66, 0x66}, > > + {0x68, 0x68}, > > + {0x6b, 0x00}, > > + {0x6c, 0x00}, > > + {0x6f, 0x40}, > > + {0x70, 0x40}, > > + {0x71, 0x0a}, > > + {0x72, 0xf0}, > > + {0x73, 0x10}, > > + {0x75, 0x80}, > > + {0x76, 0x10}, > > + {0x84, 0x00}, > > + {0x85, 0x10}, > > + {0x86, 0x10}, > > + {0x87, 0x00}, > > + {0x8a, 0x22}, > > + {0x8b, 0x22}, > > + {0x19, 0xf1}, > > + {0x29, 0x01}, > > + {0xfd, 0x01}, > > + {0x9d, 0x16}, > > + {0xa0, 0x29}, > > + {0xa1, 0x04}, > > + {0xad, 0x62}, > > + {0xae, 0x00}, > > + {0xaf, 0x85}, > > + {0xb1, 0x01}, > > + {0x8e, 0x06}, > > + {0x8f, 0x40}, > > + {0x90, 0x04}, > > + {0x91, 0xb0}, > > + {0x45, 0x01}, > > + {0x46, 0x00}, > > + {0x47, 0x6c}, > > + {0x48, 0x03}, > > + {0x49, 0x8b}, > > + {0x4a, 0x00}, > > + {0x4b, 0x07}, > > + {0x4c, 0x04}, > > + {0x4d, 0xb7}, > > + {0xf0, 0x40}, > > + {0xf1, 0x40}, > > + {0xf2, 0x40}, > > + {0xf3, 0x40}, > > + {0x3f, 0x00}, > > + {0xfd, 0x01}, > > + {0x05, 0x00}, > > + {0x06, 0xa6}, > > + {0xfd, 0x01}, > > +}; > > + > > +static const char * const ov02a10_test_pattern_menu[] = { > > + "Disabled", > > + "Eight Vertical Colour Bars", > > +}; > > + > > +static const s64 link_freq_menu_items[] = { > > + OV02A10_LINK_FREQ_390MHZ, > > +}; > > + > > +static u64 to_pixel_rate(u32 f_index) > > +{ > > + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV02A10_DATA_LANES; > > + > > + do_div(pixel_rate, OV02A10_BITS_PER_SAMPLE); > > + > > + return pixel_rate; > > +} > > + > > +static const struct ov02a10_mode supported_modes[] = { > > + { > > + .width = 1600, > > + .height = 1200, > > + .exp_def = 0x01ae, > > + .hts_def = 0x03a6, > > + .vts_def = 0x056e, > > + .reg_list = { > > + .num_of_regs = ARRAY_SIZE(ov02a10_1600x1200_regs), > > + .regs = ov02a10_1600x1200_regs, > > + }, > > + }, > > +}; > > + > > +static int ov02a10_write_array(struct ov02a10 *ov02a10, > > + const struct ov02a10_reg_list *r_list) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + unsigned int i; > > + int ret; > > + > > + for (i = 0; i < r_list->num_of_regs; i++) { > > + ret = i2c_smbus_write_byte_data(client, r_list->regs[i].addr, > > + r_list->regs[i].val); > > + if (ret < 0) > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > +static int ov02a10_read_smbus(struct ov02a10 *ov02a10, unsigned char reg, > > + unsigned char *val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_read_byte_data(client, reg); > > + if (ret < 0) > > + return ret; > > + > > + *val = (unsigned char)ret; > > No sure why you have casting and why returned value is not u8. > Fine. 'unsigned char' would be replaced of 'u8' in next release. > > + return 0; > > +} > > + > > +static void ov02a10_fill_fmt(const struct ov02a10_mode *mode, > > + struct v4l2_mbus_framefmt *fmt) > > +{ > > + fmt->width = mode->width; > > + fmt->height = mode->height; > > + fmt->field = V4L2_FIELD_NONE; > > +} > > + > > +static int ov02a10_set_fmt(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_format *fmt) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; > > + struct v4l2_mbus_framefmt *frame_fmt; > > + int ret = 0; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (ov02a10->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { > > + ret = -EBUSY; > > + goto error; > > + } > > + > > + /* Only one sensor mode supported */ > > + mbus_fmt->code = ov02a10->fmt.code; > > + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); > > + > > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) > > + frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); > > + else > > + frame_fmt = &ov02a10->fmt; > > + > > + *frame_fmt = *mbus_fmt; > > + > > +error: > > Like in other places be more precise > > out_unlock: > Sounds good naming. Fixed in next release. > > + mutex_unlock(&ov02a10->mutex); > > + return ret; > > +} > > + > > +static int ov02a10_get_fmt(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_format *fmt) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > > + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); > > + } else { > > + fmt->format = ov02a10->fmt; > > + mbus_fmt->code = ov02a10->fmt.code; > > + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); > > + } > > + > > + mutex_unlock(&ov02a10->mutex); > > + > > + return 0; > > +} > > + > > +static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_mbus_code_enum *code) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + if (code->index != 0) > > + return -EINVAL; > > + > > + code->code = ov02a10->fmt.code; > > + > > + return 0; > > +} > > + > > +static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg, > > + struct v4l2_subdev_frame_size_enum *fse) > > +{ > > + if (fse->index >= ARRAY_SIZE(supported_modes)) > > + return -EINVAL; > > + > > + fse->min_width = supported_modes[fse->index].width; > > + fse->max_width = supported_modes[fse->index].width; > > + fse->max_height = supported_modes[fse->index].height; > > + fse->min_height = supported_modes[fse->index].height; > > + > > + return 0; > > +} > > + > > +static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + u16 id; > > + u8 chip_id_h; > > + u8 chip_id_l; > > + int ret; > > + > > + /* Check sensor revision */ > > + ret = ov02a10_read_smbus(ov02a10, OV02A10_REG_CHIP_ID_H, &chip_id_h); > > + if (ret) > > + return ret; > > + > > + ret = ov02a10_read_smbus(ov02a10, OV02A10_REG_CHIP_ID_L, &chip_id_l); > > + if (ret) > > + return ret; > > I'm wondering if above can be done in one bulk transfer (reading 16-bit value). > > > + id = (chip_id_h << 8) | chip_id_l; > > If above can be achieved, this one should be rather something like > le16_to_cpu() (or be16) with corresponding type of chip_id. > Yes. i2c_smbus_read_word_data() functions could read both registers in using a single i2c transaction. Let me try locally first. > > + if (id != CHIP_ID) { > > + dev_err(&client->dev, "Unexpected sensor id(%04x)\n", id); > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int ov02a10_power_on(struct device *dev) > > +{ > > > + struct i2c_client *client = to_i2c_client(dev); > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > struct v4l2_subdev *sd = dev_get_drvdata(dev); > > Same for the rest similar cases. > We've discussed the issue in DW9768 V2. For V4L2 sub-device drivers, dev_get_drvdata() shouldn't be used directly. More details please check the Google Issue: https://partnerissuetracker.corp.google.com/issues/147957975 > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + int ret; > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); > > + > > + ret = clk_prepare_enable(ov02a10->eclk); > > + if (ret < 0) { > > + dev_err(dev, "failed to enable eclk\n"); > > + return ret; > > + } > > + > > + ret = regulator_bulk_enable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + if (ret < 0) { > > + dev_err(dev, "failed to enable regulators\n"); > > + goto disable_clk; > > + } > > + usleep_range(5000, 6000); > > + > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 0); > > + usleep_range(5000, 6000); > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 0); > > + usleep_range(5000, 6000); > > + > > + ret = ov02a10_check_sensor_id(ov02a10); > > + if (ret) > > + goto disable_regulator; > > + > > + return 0; > > + > > +disable_regulator: > > + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > +disable_clk: > > + clk_disable_unprepare(ov02a10->eclk); > > + > > + return ret; > > +} > > + > > +static int ov02a10_power_off(struct device *dev) > > +{ > > + struct i2c_client *client = to_i2c_client(dev); > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); > > + clk_disable_unprepare(ov02a10->eclk); > > + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); > > + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + > > + return 0; > > +} > > + > > +static int __ov02a10_start_stream(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + const struct ov02a10_reg_list *reg_list; > > + int ret; > > + > > + /* Apply default values of current mode */ > > + reg_list = &ov02a10->cur_mode->reg_list; > > + ret = ov02a10_write_array(ov02a10, reg_list); > > + if (ret) > > + return ret; > > + > > + /* Apply customized values from user */ > > + ret = __v4l2_ctrl_handler_setup(ov02a10->subdev.ctrl_handler); > > + if (ret) > > + return ret; > > + > > + /* Set orientation to 180 degree */ > > + if (ov02a10->upside_down) { > > + ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, > > + REG_MIRROR_FLIP_ENABLE); > > + if (ret) { > > + dev_err(&client->dev, "failed to set orientation\n"); > > + return ret; > > + } > > + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + } > > + > > + /* Set MIPI TX speed according to DT property */ > > + if (ov02a10->mipi_clock_voltage != OV02A10_MIPI_TX_SPEED_DEFAULT) { > > + ret = i2c_smbus_write_byte_data(client, TX_SPEED_AREA_SEL, > > + ov02a10->mipi_clock_voltage); > > + if (ret < 0) > > + return ret; > > + } > > + > > + /* Set stream on register */ > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STREAMING); > > +} > > + > > +static int __ov02a10_stop_stream(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STANDBY); > > +} > > + > > +static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd, > > + struct v4l2_subdev_pad_config *cfg) > > +{ > > + struct v4l2_subdev_format fmt = { > > + .which = V4L2_SUBDEV_FORMAT_TRY, > > + .format = { > > + .width = 1600, > > + .height = 1200, > > + } > > + }; > > + > > + ov02a10_set_fmt(sd, cfg, &fmt); > > + > > + return 0; > > +} > > + > > +static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) > > +{ > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + mutex_lock(&ov02a10->mutex); > > + > > + if (ov02a10->streaming == on) > > + goto unlock_and_return; > > + > > + if (on) { > > + ret = pm_runtime_get_sync(&client->dev); > > + if (ret < 0) { > > + pm_runtime_put_noidle(&client->dev); > > + goto unlock_and_return; > > + } > > + > > + ret = __ov02a10_start_stream(ov02a10); > > + if (ret) { > > + __ov02a10_stop_stream(ov02a10); > > + ov02a10->streaming = !on; > > + goto err_rpm_put; > > + } > > + } else { > > + __ov02a10_stop_stream(ov02a10); > > + pm_runtime_put(&client->dev); > > + } > > + > > + ov02a10->streaming = on; > > + mutex_unlock(&ov02a10->mutex); > > + > > + return 0; > > + > > +err_rpm_put: > > + pm_runtime_put(&client->dev); > > +unlock_and_return: > > + mutex_unlock(&ov02a10->mutex); > > + > > + return ret; > > +} > > + > > +static const struct dev_pm_ops ov02a10_pm_ops = { > > + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > > + pm_runtime_force_resume) > > + SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) > > +}; > > + > > +/* > > + * ov02a10_set_exposure - Function called when setting exposure time > > + * @priv: Pointer to device structure > > + * @val: Variable for exposure time, in the unit of micro-second > > + * > > + * Set exposure time based on input value. > > + * > > + * Return: 0 on success > > + */ > > +static int ov02a10_set_exposure(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_H, > > + val >> OV02A10_EXP_SHIFT); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_L, val); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_gain(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_GAIN, val); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_vblank(struct ov02a10 *ov02a10, int val) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + u32 vts = val + ov02a10->cur_mode->height - OV02A10_BASIC_LINE; > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_H, > > + vts >> OV02A10_VTS_SHIFT); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_L, vts); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > +} > > + > > +static int ov02a10_set_test_pattern(struct ov02a10 *ov02a10, int pattern) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + int ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_TEST_PATTERN, > > + pattern); > > + if (ret < 0) > > + return ret; > > + > > + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, > > + REG_ENABLE); > > + if (ret < 0) > > + return ret; > > + > > + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, > > + SC_CTRL_MODE_STREAMING); > > +} > > + > > +static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) > > +{ > > + struct ov02a10 *ov02a10 = container_of(ctrl->handler, > > + struct ov02a10, ctrl_handler); > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + s64 max_expo; > > + int ret; > > + > > + /* Propagate change of current control to all related controls */ > > + if (ctrl->id == V4L2_CID_VBLANK) { > > + /* Update max exposure while meeting expected vblanking */ > > + max_expo = ov02a10->cur_mode->height + ctrl->val - > > + OV02A10_EXPOSURE_MAX_MARGIN; > > + __v4l2_ctrl_modify_range(ov02a10->exposure, > > + ov02a10->exposure->minimum, max_expo, > > + ov02a10->exposure->step, > > + ov02a10->exposure->default_value); > > + } > > + > > + /* V4L2 controls values will be applied only when power is already up */ > > + if (!pm_runtime_get_if_in_use(&client->dev)) > > + return 0; > > + > > + switch (ctrl->id) { > > + case V4L2_CID_EXPOSURE: > > + ret = ov02a10_set_exposure(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_ANALOGUE_GAIN: > > + ret = ov02a10_set_gain(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_VBLANK: > > + ret = ov02a10_set_vblank(ov02a10, ctrl->val); > > + break; > > + case V4L2_CID_TEST_PATTERN: > > + ret = ov02a10_set_test_pattern(ov02a10, ctrl->val); > > + break; > > + default: > > + ret = -EINVAL; > > + break; > > + }; > > + > > + pm_runtime_put(&client->dev); > > + > > + return ret; > > +} > > + > > +static const struct v4l2_subdev_video_ops ov02a10_video_ops = { > > + .s_stream = ov02a10_s_stream, > > +}; > > + > > +static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = { > > + .init_cfg = ov02a10_entity_init_cfg, > > + .enum_mbus_code = ov02a10_enum_mbus_code, > > + .enum_frame_size = ov02a10_enum_frame_sizes, > > + .get_fmt = ov02a10_get_fmt, > > + .set_fmt = ov02a10_set_fmt, > > +}; > > + > > +static const struct v4l2_subdev_ops ov02a10_subdev_ops = { > > + .video = &ov02a10_video_ops, > > + .pad = &ov02a10_pad_ops, > > +}; > > + > > +static const struct media_entity_operations ov02a10_subdev_entity_ops = { > > + .link_validate = v4l2_subdev_link_validate, > > +}; > > + > > +static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { > > + .s_ctrl = ov02a10_set_ctrl, > > +}; > > + > > +static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) > > +{ > > + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); > > + const struct ov02a10_mode *mode; > > + struct v4l2_ctrl_handler *handler; > > + struct v4l2_ctrl *ctrl; > > + s64 exposure_max; > > + s64 vblank_def; > > + s64 pixel_rate; > > + s64 h_blank; > > + int ret; > > + > > + handler = &ov02a10->ctrl_handler; > > + mode = ov02a10->cur_mode; > > + ret = v4l2_ctrl_handler_init(handler, 7); > > + if (ret) > > + return ret; > > + > > + handler->lock = &ov02a10->mutex; > > + > > + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, > > + link_freq_menu_items); > > + if (ctrl) > > + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > + > > + pixel_rate = to_pixel_rate(0); > > + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, > > + pixel_rate); > > + > > + h_blank = mode->hts_def - mode->width; > > + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, > > + h_blank); > > + > > + vblank_def = mode->vts_def - mode->height; > > + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, V4L2_CID_VBLANK, > > + vblank_def, OV02A10_VTS_MAX - mode->height, 1, > > + vblank_def); > > + > > + exposure_max = mode->vts_def - 4; > > + ov02a10->exposure = v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_EXPOSURE, > > + OV02A10_EXPOSURE_MIN, > > + exposure_max, > > + OV02A10_EXPOSURE_STEP, > > + mode->exp_def); > > + > > + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_ANALOGUE_GAIN, OV02A10_GAIN_MIN, > > + OV02A10_GAIN_MAX, OV02A10_GAIN_STEP, > > + OV02A10_GAIN_DEFAULT); > > + > > + v4l2_ctrl_new_std_menu_items(handler, &ov02a10_ctrl_ops, > > + V4L2_CID_TEST_PATTERN, > > + ARRAY_SIZE(ov02a10_test_pattern_menu) - 1, > > + 0, 0, ov02a10_test_pattern_menu); > > + > > + if (handler->error) { > > + ret = handler->error; > > + dev_err(&client->dev, "failed to init controls(%d)\n", ret); > > + goto err_free_handler; > > + } > > + > > + ov02a10->subdev.ctrl_handler = handler; > > + > > + return 0; > > + > > +err_free_handler: > > + v4l2_ctrl_handler_free(handler); > > + > > + return ret; > > +} > > + > > +static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) > > +{ > > + struct fwnode_handle *ep; > > + struct fwnode_handle *fwnode = dev_fwnode(dev); > > + struct v4l2_fwnode_endpoint bus_cfg = { > > + .bus_type = V4L2_MBUS_CSI2_DPHY, > > + }; > > + unsigned int i, j; > > + int ret; > > + > > + if (!fwnode) > > + return -EINVAL; > > + > > + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); > > + if (!ep) > > + return -ENXIO; > > + > > + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); > > + fwnode_handle_put(ep); > > + if (ret) > > + return ret; > > + > > + if (!bus_cfg.nr_of_link_frequencies) { > > + dev_err(dev, "no link frequencies defined\n"); > > + ret = -EINVAL; > > + goto check_hwcfg_error; > > + } > > If it's 0, the below will break on 'if (j == 0)' with slightly different but > informative enough message. What do you keep above check for? > I still prefer to the original version. If 'bus_cfg.nr_of_link_frequencies' is 0, shouldn't we directly return error? > > + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { > > + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { > > + if (link_freq_menu_items[i] == > > + bus_cfg.link_frequencies[j]) { > > + ov02a10->freq_index = i; > > + break; > > + } > > + } > > + > > + if (j == bus_cfg.nr_of_link_frequencies) { > > + dev_err(dev, "no link frequency %lld supported\n", > > + link_freq_menu_items[i]); > > + ret = -EINVAL; > > > + goto check_hwcfg_error; > > 'break;' won't work? > > > + } > > + } > > + > > +check_hwcfg_error: > > out_endpoint_free: > It seems that OV8856 keeps the same pattern. > > + v4l2_fwnode_endpoint_free(&bus_cfg); > > + > > + return ret; > > +} > > + > > +static int ov02a10_probe(struct i2c_client *client) > > +{ > > + struct device *dev = &client->dev; > > + struct ov02a10 *ov02a10; > > + unsigned int rotation; > > + unsigned int cnt = 0; > > + unsigned int i; > > > + unsigned int num_freq_clk_volt = 2 * ARRAY_SIZE(link_freq_menu_items); > > Can it be moved upper to improve readability? > Fixed in next release. > > + int ret; > > + > > + ov02a10 = devm_kzalloc(dev, sizeof(*ov02a10), GFP_KERNEL); > > + if (!ov02a10) > > + return -ENOMEM; > > + > > + ret = ov02a10_check_hwcfg(dev, ov02a10); > > + if (ret) { > > + dev_err(dev, "failed to check HW configuration: %d\n", ret); > > + return ret; > > + } > > + > > + v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops); > > + ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT; > > + ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; > > + > > + /* Optional indication of physical rotation of sensor */ > > + ret = fwnode_property_read_u32(dev_fwnode(dev), "rotation", &rotation); > > + if (!ret && rotation == 180) { > > Can be simplified (but I'm fine with above): > > unsigned int rotation = 0; > ... > fwnode_property_read_u32(..., &rotation); > if (rotation == 180) { > ... > } > Sounds like the readability is improved using the latter style :-) > > + ov02a10->upside_down = true; > > + ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; > > + } > > + > > + /* Optional indication of MIPI clock voltage unit */ > > + ret = fwnode_property_read_u32_array(dev_fwnode(dev), > > + "ovti,mipi-clock-voltage", NULL, > > + 0); > > ret = fwnode_property_count_u32(...); // will be one line > Great APIs! > > + if (ret > 0 && ret % 2 == 0) { > > + u32 freq_clk_volt[ret]; > > + > > + fwnode_property_read_u32_array(dev_fwnode(dev), > > + "ovti,mipi-clock-voltage", > > + freq_clk_volt, > > + ARRAY_SIZE(freq_clk_volt)); > > + > > + while (num_freq_clk_volt) { > > + unsigned long freq; > > + unsigned long volt; > > + > > + if (cnt >= ARRAY_SIZE(freq_clk_volt)) { > > + dev_warn(dev, "mismatched link frequency\n"); > > + break; > > + } > > + > > > + freq = freq_clk_volt[cnt++] * 1000; > > HZ_PER_KHZ? > Fixed in next release. > > + volt = freq_clk_volt[cnt++]; > > + > > + /* Get clock voltage unit value from DT */ > > + if (freq == link_freq_menu_items[ov02a10->freq_index]) { > > + ov02a10->mipi_clock_voltage = volt; > > + break; > > + } > > + > > + num_freq_clk_volt -= 2; > > + } > > + } > > + > > + /* Get external input clock (eclk) */ > > + ov02a10->eclk = devm_clk_get(dev, "eclk"); > > + if (IS_ERR(ov02a10->eclk)) { > > + ret = PTR_ERR(ov02a10->eclk); > > + dev_err(dev, "failed to get eclk %d\n", ret); > > + return ret; > > return dev_err_probe(...); > Great APIs... > > + } > > + > > + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", > > + &ov02a10->eclk_freq); > > + if (ret) { > > + dev_err(dev, "failed to get eclk frequency\n"); > > + return ret; > > + } > > > + ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); > > + if (ret) { > > + dev_err(dev, "failed to set eclk frequency (24MHz)\n"); > > + return ret; > > + } > > + > > + if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) { > > + dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); > > + return -EINVAL; > > + } > > + > > + ov02a10->pd_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); > > + if (IS_ERR(ov02a10->pd_gpio)) { > > > + ret = PTR_ERR(ov02a10->pd_gpio); > > + dev_err(dev, "failed to get powerdown-gpios %d\n", ret); > > + return ret; > > return dev_err_probe(...); > It would be simplified using dev_err_probe directly in next release. > > + } > > + > > + ov02a10->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); > > + if (IS_ERR(ov02a10->rst_gpio)) { > > + ret = PTR_ERR(ov02a10->rst_gpio); > > + dev_err(dev, "failed to get reset-gpios %d\n", ret); > > + return ret; > > Ditto. > Fixed in next release. > > + } > > + > > + for (i = 0; i < ARRAY_SIZE(ov02a10_supply_names); i++) > > + ov02a10->supplies[i].supply = ov02a10_supply_names[i]; > > + > > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov02a10_supply_names), > > + ov02a10->supplies); > > + if (ret) { > > > + dev_err(dev, "failed to get regulators\n"); > > + return ret; > > Ditto. > Fixed in next release. > > + } > > + > > + mutex_init(&ov02a10->mutex); > > + ov02a10->cur_mode = &supported_modes[0]; > > + > > + ret = ov02a10_initialize_controls(ov02a10); > > + if (ret) { > > + dev_err(dev, "failed to initialize controls\n"); > > + goto err_destroy_mutex; > > + } > > + > > + ov02a10->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; > > + ov02a10->subdev.entity.ops = &ov02a10_subdev_entity_ops; > > + ov02a10->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; > > + ov02a10->pad.flags = MEDIA_PAD_FL_SOURCE; > > + > > + ret = media_entity_pads_init(&ov02a10->subdev.entity, 1, &ov02a10->pad); > > + if (ret < 0) { > > + dev_err(dev, "failed to init entity pads: %d", ret); > > + goto err_free_handler; > > + } > > + > > + pm_runtime_enable(dev); > > + if (!pm_runtime_enabled(dev)) { > > + ret = ov02a10_power_on(dev); > > + if (ret < 0) { > > + dev_err(dev, "failed to power on: %d\n", ret); > > + goto err_clean_entity; > > + } > > + } > > + > > + ret = v4l2_async_register_subdev(&ov02a10->subdev); > > + if (ret) { > > + dev_err(dev, "failed to register V4L2 subdev: %d\n", ret); > > + goto err_power_off; > > + } > > + > > + return 0; > > + > > +err_power_off: > > + if (pm_runtime_enabled(dev)) > > + pm_runtime_disable(dev); > > + else > > + ov02a10_power_off(dev); > > +err_clean_entity: > > + media_entity_cleanup(&ov02a10->subdev.entity); > > +err_free_handler: > > + v4l2_ctrl_handler_free(ov02a10->subdev.ctrl_handler); > > +err_destroy_mutex: > > + mutex_destroy(&ov02a10->mutex); > > + > > + return ret; > > +} > > + > > +static int ov02a10_remove(struct i2c_client *client) > > +{ > > + struct v4l2_subdev *sd = i2c_get_clientdata(client); > > + struct ov02a10 *ov02a10 = to_ov02a10(sd); > > + > > + v4l2_async_unregister_subdev(sd); > > + media_entity_cleanup(&sd->entity); > > + v4l2_ctrl_handler_free(sd->ctrl_handler); > > + pm_runtime_disable(&client->dev); > > + if (!pm_runtime_status_suspended(&client->dev)) > > + ov02a10_power_off(&client->dev); > > + pm_runtime_set_suspended(&client->dev); > > + mutex_destroy(&ov02a10->mutex); > > + > > + return 0; > > +} > > + > > +static const struct of_device_id ov02a10_of_match[] = { > > + { .compatible = "ovti,ov02a10" }, > > + {} > > +}; > > +MODULE_DEVICE_TABLE(of, ov02a10_of_match); > > + > > +static struct i2c_driver ov02a10_i2c_driver = { > > + .driver = { > > + .name = "ov02a10", > > + .pm = &ov02a10_pm_ops, > > + .of_match_table = ov02a10_of_match, > > + }, > > + .probe_new = &ov02a10_probe, > > + .remove = &ov02a10_remove, > > +}; > > > + > > Redundant blank line. > Fixed in next release. > > +module_i2c_driver(ov02a10_i2c_driver); > > + > > +MODULE_AUTHOR("Dongchun Zhu "); > > +MODULE_DESCRIPTION("OmniVision OV02A10 sensor driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.9.2 > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel