diff for duplicates of <1427633859-18596-2-git-send-email-pali.rohar@gmail.com> diff --git a/a/1.txt b/N1/1.txt index 2004e55..e4aa265 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -1,924 +1,2085 @@ -VGhpcyBjb21taXQgbW92ZXMgaThrIGRyaXZlciB0byBod21vbiB0cmVlIHVuZGVyIG5hbWUgZGVs -bC1zbW0taHdtb24gd2hpY2ggaXMKYmV0dGVyIG5hbWUgdGhlbiBhYmJyZXZpYXRpb24gaThrLiBG -b3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBpcyBhZGRlZCBtYWNybwpNT0RVTEVfQUxJQVMoImk4 -ayIpIHNvIG1vZHByb2JlIHdpbGwgbG9hZCBkcml2ZXIgYWxzbyBvbGQgbmFtZSBpOGsuIENPTkZJ -R19JOEsKY29tcGlsZSBvcHRpb24gd2FzIG5vdCBjaGFuZ2VkLgoKVGhpcyBjb21taXQgYWxzbyBh -ZGRzIG1lIGFzIG1haW50YWluZXIgb2YgdGhpcyBuZXcgZGVsbC1zbW0taHdtb24gZHJpdmVyIGFu -ZApyZW1vdmUgR3VlbnRlciBSb2VjayBmcm9tIGxpc3Qgd2hvIGlzIGltcGxpY2l0IG1haW50YWlu -ZXIgYWxsIGh3bW9uIGRyaXZlcnMuCgpTaWduZWQtb2ZmLWJ5OiBQYWxpIFJvaMOhciA8cGFsaS5y -b2hhckBnbWFpbC5jb20+Ci0tLQogTUFJTlRBSU5FUlMgICAgICAgICAgICAgICAgICAgIHwgICAg -NCArLQogZHJpdmVycy9jaGFyL01ha2VmaWxlICAgICAgICAgIHwgICAgMSAtCiBkcml2ZXJzL2No -YXIvaThrLmMgICAgICAgICAgICAgfCAxMDA1IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t -LS0tLS0tLS0tLQogZHJpdmVycy9od21vbi9NYWtlZmlsZSAgICAgICAgIHwgICAgMSArCiBkcml2 -ZXJzL2h3bW9uL2RlbGwtc21tLWh3bW9uLmMgfCAxMDA3ICsrKysrKysrKysrKysrKysrKysrKysr -KysrKysrKysrKysrKysrKysKIDUgZmlsZXMgY2hhbmdlZCwgMTAxMCBpbnNlcnRpb25zKCspLCAx -MDA4IGRlbGV0aW9ucygtKQogZGVsZXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvY2hhci9pOGsuYwog -Y3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaHdtb24vZGVsbC1zbW0taHdtb24uYwoKZGlmZiAt -LWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRBSU5FUlMKaW5kZXggODhjMDljYS4uZTU0YTA3ZSAx -MDA2NDQKLS0tIGEvTUFJTlRBSU5FUlMKKysrIGIvTUFJTlRBSU5FUlMKQEAgLTMwNjMsOSArMzA2 -Myw5IEBAIFM6CU1haW50YWluZWQKIEY6CWRyaXZlcnMvcGxhdGZvcm0veDg2L2RlbGwtbGFwdG9w -LmMKIAogREVMTCBMQVBUT1AgU01NIERSSVZFUgotTToJR3VlbnRlciBSb2VjayA8bGludXhAcm9l -Y2stdXMubmV0PgorTToJUGFsaSBSb2jDoXIgPHBhbGkucm9oYXJAZ21haWwuY29tPgogUzoJTWFp -bnRhaW5lZAotRjoJZHJpdmVycy9jaGFyL2k4ay5jCitGOglkcml2ZXJzL2h3bW9uL2RlbGwtc21t -LWh3bW9uLmMKIEY6CWluY2x1ZGUvdWFwaS9saW51eC9pOGsuaAogCiBERUxMIFNZU1RFTVMgTUFO -QUdFTUVOVCBCQVNFIERSSVZFUiAoZGNkYmFzKQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL01h -a2VmaWxlIGIvZHJpdmVycy9jaGFyL01ha2VmaWxlCmluZGV4IGQwNmNkZTI2Li4xZDljZjAwIDEw -MDY0NAotLS0gYS9kcml2ZXJzL2NoYXIvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9jaGFyL01ha2Vm -aWxlCkBAIC0zNiw3ICszNiw2IEBAIGVsc2UKICAgb2JqLSQoQ09ORklHX05WUkFNKQkrPSBudnJh -bS5vCiBlbmRpZgogb2JqLSQoQ09ORklHX1RPU0hJQkEpCQkrPSB0b3NoaWJhLm8KLW9iai0kKENP -TkZJR19JOEspCQkrPSBpOGsubwogb2JqLSQoQ09ORklHX0RTMTYyMCkJCSs9IGRzMTYyMC5vCiBv -YmotJChDT05GSUdfSFdfUkFORE9NKQkJKz0gaHdfcmFuZG9tLwogb2JqLSQoQ09ORklHX1BQREVW -KQkJKz0gcHBkZXYubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2k4ay5jIGIvZHJpdmVycy9j -aGFyL2k4ay5jCmRlbGV0ZWQgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAyNGNjNGVkLi4wMDAwMDAw -Ci0tLSBhL2RyaXZlcnMvY2hhci9pOGsuYworKysgL2Rldi9udWxsCkBAIC0xLDEwMDUgKzAsMCBA -QAotLyoKLSAqIGk4ay5jIC0tIExpbnV4IGRyaXZlciBmb3IgYWNjZXNzaW5nIHRoZSBTTU0gQklP -UyBvbiBEZWxsIGxhcHRvcHMuCi0gKgotICogQ29weXJpZ2h0IChDKSAyMDAxICBNYXNzaW1vIERh -bCBab3R0byA8ZHpAZGViaWFuLm9yZz4KLSAqCi0gKiBId21vbiBpbnRlZ3JhdGlvbjoKLSAqIENv -cHlyaWdodCAoQykgMjAxMSAgSmVhbiBEZWx2YXJlIDxqZGVsdmFyZUBzdXNlLmRlPgotICogQ29w -eXJpZ2h0IChDKSAyMDEzLCAyMDE0ICBHdWVudGVyIFJvZWNrIDxsaW51eEByb2Vjay11cy5uZXQ+ -Ci0gKiBDb3B5cmlnaHQgKEMpIDIwMTQgIFBhbGkgUm9ow6FyIDxwYWxpLnJvaGFyQGdtYWlsLmNv -bT4KLSAqCi0gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3Ry -aWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdAotICogdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUg -R2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlCi0gKiBGcmVlIFNvZnR3 -YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55 -Ci0gKiBsYXRlciB2ZXJzaW9uLgotICoKLSAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBp -biB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQKLSAqIFdJVEhPVVQgQU5ZIFdB -UlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKLSAqIE1FUkNIQU5U -QUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05V -Ci0gKiBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCi0gKi8KLQotI2Rl -ZmluZSBwcl9mbXQoZm10KSBLQlVJTERfTU9ETkFNRSAiOiAiIGZtdAotCi0jaW5jbHVkZSA8bGlu -dXgvZGVsYXkuaD4KLSNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KLSNpbmNsdWRlIDxsaW51eC90 -eXBlcy5oPgotI2luY2x1ZGUgPGxpbnV4L2luaXQuaD4KLSNpbmNsdWRlIDxsaW51eC9wcm9jX2Zz -Lmg+Ci0jaW5jbHVkZSA8bGludXgvc2VxX2ZpbGUuaD4KLSNpbmNsdWRlIDxsaW51eC9kbWkuaD4K -LSNpbmNsdWRlIDxsaW51eC9jYXBhYmlsaXR5Lmg+Ci0jaW5jbHVkZSA8bGludXgvbXV0ZXguaD4K -LSNpbmNsdWRlIDxsaW51eC9od21vbi5oPgotI2luY2x1ZGUgPGxpbnV4L2h3bW9uLXN5c2ZzLmg+ -Ci0jaW5jbHVkZSA8bGludXgvdWFjY2Vzcy5oPgotI2luY2x1ZGUgPGxpbnV4L2lvLmg+Ci0jaW5j -bHVkZSA8bGludXgvc2NoZWQuaD4KLQotI2luY2x1ZGUgPGxpbnV4L2k4ay5oPgotCi0jZGVmaW5l -IEk4S19TTU1fRk5fU1RBVFVTCTB4MDAyNQotI2RlZmluZSBJOEtfU01NX1BPV0VSX1NUQVRVUwkw -eDAwNjkKLSNkZWZpbmUgSThLX1NNTV9TRVRfRkFOCQkweDAxYTMKLSNkZWZpbmUgSThLX1NNTV9H -RVRfRkFOCQkweDAwYTMKLSNkZWZpbmUgSThLX1NNTV9HRVRfU1BFRUQJMHgwMmEzCi0jZGVmaW5l -IEk4S19TTU1fR0VUX0ZBTl9UWVBFCTB4MDNhMwotI2RlZmluZSBJOEtfU01NX0dFVF9OT01fU1BF -RUQJMHgwNGEzCi0jZGVmaW5lIEk4S19TTU1fR0VUX1RFTVAJMHgxMGEzCi0jZGVmaW5lIEk4S19T -TU1fR0VUX1RFTVBfVFlQRQkweDExYTMKLSNkZWZpbmUgSThLX1NNTV9HRVRfREVMTF9TSUcxCTB4 -ZmVhMwotI2RlZmluZSBJOEtfU01NX0dFVF9ERUxMX1NJRzIJMHhmZmEzCi0KLSNkZWZpbmUgSThL -X0ZBTl9NVUxUCQkzMAotI2RlZmluZSBJOEtfRkFOX01BWF9SUE0JCTMwMDAwCi0jZGVmaW5lIEk4 -S19NQVhfVEVNUAkJMTI3Ci0KLSNkZWZpbmUgSThLX0ZOX05PTkUJCTB4MDAKLSNkZWZpbmUgSThL -X0ZOX1VQCQkweDAxCi0jZGVmaW5lIEk4S19GTl9ET1dOCQkweDAyCi0jZGVmaW5lIEk4S19GTl9N -VVRFCQkweDA0Ci0jZGVmaW5lIEk4S19GTl9NQVNLCQkweDA3Ci0jZGVmaW5lIEk4S19GTl9TSElG -VAkJOAotCi0jZGVmaW5lIEk4S19QT1dFUl9BQwkJMHgwNQotI2RlZmluZSBJOEtfUE9XRVJfQkFU -VEVSWQkweDAxCi0KLXN0YXRpYyBERUZJTkVfTVVURVgoaThrX211dGV4KTsKLXN0YXRpYyBjaGFy -IGJpb3NfdmVyc2lvbls0XTsKLXN0YXRpYyBzdHJ1Y3QgZGV2aWNlICppOGtfaHdtb25fZGV2Owot -c3RhdGljIHUzMiBpOGtfaHdtb25fZmxhZ3M7Ci1zdGF0aWMgdWludCBpOGtfZmFuX211bHQgPSBJ -OEtfRkFOX01VTFQ7Ci1zdGF0aWMgdWludCBpOGtfcHdtX211bHQ7Ci1zdGF0aWMgdWludCBpOGtf -ZmFuX21heCA9IEk4S19GQU5fSElHSDsKLQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1QMQko -MSA8PCAwKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1QMgkoMSA8PCAxKQotI2RlZmluZSBJ -OEtfSFdNT05fSEFWRV9URU1QMwkoMSA8PCAyKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1Q -NAkoMSA8PCAzKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9GQU4xCSgxIDw8IDQpCi0jZGVmaW5l -IEk4S19IV01PTl9IQVZFX0ZBTjIJKDEgPDwgNSkKLQotTU9EVUxFX0FVVEhPUigiTWFzc2ltbyBE -YWwgWm90dG8gKGR6QGRlYmlhbi5vcmcpIik7Ci1NT0RVTEVfREVTQ1JJUFRJT04oIkRyaXZlciBm -b3IgYWNjZXNzaW5nIFNNTSBCSU9TIG9uIERlbGwgbGFwdG9wcyIpOwotTU9EVUxFX0xJQ0VOU0Uo -IkdQTCIpOwotCi1zdGF0aWMgYm9vbCBmb3JjZTsKLW1vZHVsZV9wYXJhbShmb3JjZSwgYm9vbCwg -MCk7Ci1NT0RVTEVfUEFSTV9ERVNDKGZvcmNlLCAiRm9yY2UgbG9hZGluZyB3aXRob3V0IGNoZWNr -aW5nIGZvciBzdXBwb3J0ZWQgbW9kZWxzIik7Ci0KLXN0YXRpYyBib29sIGlnbm9yZV9kbWk7Ci1t -b2R1bGVfcGFyYW0oaWdub3JlX2RtaSwgYm9vbCwgMCk7Ci1NT0RVTEVfUEFSTV9ERVNDKGlnbm9y -ZV9kbWksICJDb250aW51ZSBwcm9iaW5nIGhhcmR3YXJlIGV2ZW4gaWYgRE1JIGRhdGEgZG9lcyBu -b3QgbWF0Y2giKTsKLQotc3RhdGljIGJvb2wgcmVzdHJpY3RlZDsKLW1vZHVsZV9wYXJhbShyZXN0 -cmljdGVkLCBib29sLCAwKTsKLU1PRFVMRV9QQVJNX0RFU0MocmVzdHJpY3RlZCwgIkFsbG93IGZh -biBjb250cm9sIGlmIFNZU19BRE1JTiBjYXBhYmlsaXR5IHNldCIpOwotCi1zdGF0aWMgYm9vbCBw -b3dlcl9zdGF0dXM7Ci1tb2R1bGVfcGFyYW0ocG93ZXJfc3RhdHVzLCBib29sLCAwNjAwKTsKLU1P -RFVMRV9QQVJNX0RFU0MocG93ZXJfc3RhdHVzLCAiUmVwb3J0IHBvd2VyIHN0YXR1cyBpbiAvcHJv -Yy9pOGsiKTsKLQotc3RhdGljIHVpbnQgZmFuX211bHQ7Ci1tb2R1bGVfcGFyYW0oZmFuX211bHQs -IHVpbnQsIDApOwotTU9EVUxFX1BBUk1fREVTQyhmYW5fbXVsdCwgIkZhY3RvciB0byBtdWx0aXBs -eSBmYW4gc3BlZWQgd2l0aCAoZGVmYXVsdDogYXV0b2RldGVjdCkiKTsKLQotc3RhdGljIHVpbnQg -ZmFuX21heDsKLW1vZHVsZV9wYXJhbShmYW5fbWF4LCB1aW50LCAwKTsKLU1PRFVMRV9QQVJNX0RF -U0MoZmFuX21heCwgIk1heGltdW0gY29uZmlndXJhYmxlIGZhbiBzcGVlZCAoZGVmYXVsdDogYXV0 -b2RldGVjdCkiKTsKLQotc3RhdGljIGludCBpOGtfb3Blbl9mcyhzdHJ1Y3QgaW5vZGUgKmlub2Rl -LCBzdHJ1Y3QgZmlsZSAqZmlsZSk7Ci1zdGF0aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUg -KiwgdW5zaWduZWQgaW50LCB1bnNpZ25lZCBsb25nKTsKLQotc3RhdGljIGNvbnN0IHN0cnVjdCBm -aWxlX29wZXJhdGlvbnMgaThrX2ZvcHMgPSB7Ci0JLm93bmVyCQk9IFRISVNfTU9EVUxFLAotCS5v -cGVuCQk9IGk4a19vcGVuX2ZzLAotCS5yZWFkCQk9IHNlcV9yZWFkLAotCS5sbHNlZWsJCT0gc2Vx -X2xzZWVrLAotCS5yZWxlYXNlCT0gc2luZ2xlX3JlbGVhc2UsCi0JLnVubG9ja2VkX2lvY3RsCT0g -aThrX2lvY3RsLAotfTsKLQotc3RydWN0IHNtbV9yZWdzIHsKLQl1bnNpZ25lZCBpbnQgZWF4Owot -CXVuc2lnbmVkIGludCBlYnggX19wYWNrZWQ7Ci0JdW5zaWduZWQgaW50IGVjeCBfX3BhY2tlZDsK -LQl1bnNpZ25lZCBpbnQgZWR4IF9fcGFja2VkOwotCXVuc2lnbmVkIGludCBlc2kgX19wYWNrZWQ7 -Ci0JdW5zaWduZWQgaW50IGVkaSBfX3BhY2tlZDsKLX07Ci0KLXN0YXRpYyBpbmxpbmUgY29uc3Qg -Y2hhciAqaThrX2dldF9kbWlfZGF0YShpbnQgZmllbGQpCi17Ci0JY29uc3QgY2hhciAqZG1pX2Rh -dGEgPSBkbWlfZ2V0X3N5c3RlbV9pbmZvKGZpZWxkKTsKLQotCXJldHVybiBkbWlfZGF0YSAmJiAq -ZG1pX2RhdGEgPyBkbWlfZGF0YSA6ICI/IjsKLX0KLQotLyoKLSAqIENhbGwgdGhlIFN5c3RlbSBN -YW5hZ2VtZW50IE1vZGUgQklPUy4gQ29kZSBwcm92aWRlZCBieSBKb25hdGhhbiBCdXp6YXJkLgot -ICovCi1zdGF0aWMgaW50IGk4a19zbW0oc3RydWN0IHNtbV9yZWdzICpyZWdzKQotewotCWludCBy -YzsKLQlpbnQgZWF4ID0gcmVncy0+ZWF4OwotCWNwdW1hc2tfdmFyX3Qgb2xkX21hc2s7Ci0KLQkv -KiBTTU0gcmVxdWlyZXMgQ1BVIDAgKi8KLQlpZiAoIWFsbG9jX2NwdW1hc2tfdmFyKCZvbGRfbWFz -aywgR0ZQX0tFUk5FTCkpCi0JCXJldHVybiAtRU5PTUVNOwotCWNwdW1hc2tfY29weShvbGRfbWFz -aywgJmN1cnJlbnQtPmNwdXNfYWxsb3dlZCk7Ci0JcmMgPSBzZXRfY3B1c19hbGxvd2VkX3B0cihj -dXJyZW50LCBjcHVtYXNrX29mKDApKTsKLQlpZiAocmMpCi0JCWdvdG8gb3V0OwotCWlmIChzbXBf -cHJvY2Vzc29yX2lkKCkgIT0gMCkgewotCQlyYyA9IC1FQlVTWTsKLQkJZ290byBvdXQ7Ci0JfQot -Ci0jaWYgZGVmaW5lZChDT05GSUdfWDg2XzY0KQotCWFzbSB2b2xhdGlsZSgicHVzaHEgJSVyYXhc -blx0IgotCQkibW92bCAwKCUlcmF4KSwlJWVkeFxuXHQiCi0JCSJwdXNocSAlJXJkeFxuXHQiCi0J -CSJtb3ZsIDQoJSVyYXgpLCUlZWJ4XG5cdCIKLQkJIm1vdmwgOCglJXJheCksJSVlY3hcblx0Igot -CQkibW92bCAxMiglJXJheCksJSVlZHhcblx0IgotCQkibW92bCAxNiglJXJheCksJSVlc2lcblx0 -IgotCQkibW92bCAyMCglJXJheCksJSVlZGlcblx0IgotCQkicG9wcSAlJXJheFxuXHQiCi0JCSJv -dXQgJSVhbCwkMHhiMlxuXHQiCi0JCSJvdXQgJSVhbCwkMHg4NFxuXHQiCi0JCSJ4Y2hncSAlJXJh -eCwoJSVyc3ApXG5cdCIKLQkJIm1vdmwgJSVlYngsNCglJXJheClcblx0IgotCQkibW92bCAlJWVj -eCw4KCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUlZWR4LDEyKCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUl -ZXNpLDE2KCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUlZWRpLDIwKCUlcmF4KVxuXHQiCi0JCSJwb3Bx -ICUlcmR4XG5cdCIKLQkJIm1vdmwgJSVlZHgsMCglJXJheClcblx0IgotCQkicHVzaGZxXG5cdCIK -LQkJInBvcHEgJSVyYXhcblx0IgotCQkiYW5kbCAkMSwlJWVheFxuIgotCQk6ICI9YSIocmMpCi0J -CTogICAgImEiKHJlZ3MpCi0JCTogICAgIiVlYngiLCAiJWVjeCIsICIlZWR4IiwgIiVlc2kiLCAi -JWVkaSIsICJtZW1vcnkiKTsKLSNlbHNlCi0JYXNtIHZvbGF0aWxlKCJwdXNobCAlJWVheFxuXHQi -Ci0JICAgICJtb3ZsIDAoJSVlYXgpLCUlZWR4XG5cdCIKLQkgICAgInB1c2ggJSVlZHhcblx0Igot -CSAgICAibW92bCA0KCUlZWF4KSwlJWVieFxuXHQiCi0JICAgICJtb3ZsIDgoJSVlYXgpLCUlZWN4 -XG5cdCIKLQkgICAgIm1vdmwgMTIoJSVlYXgpLCUlZWR4XG5cdCIKLQkgICAgIm1vdmwgMTYoJSVl -YXgpLCUlZXNpXG5cdCIKLQkgICAgIm1vdmwgMjAoJSVlYXgpLCUlZWRpXG5cdCIKLQkgICAgInBv -cGwgJSVlYXhcblx0IgotCSAgICAib3V0ICUlYWwsJDB4YjJcblx0IgotCSAgICAib3V0ICUlYWws -JDB4ODRcblx0IgotCSAgICAieGNoZ2wgJSVlYXgsKCUlZXNwKVxuXHQiCi0JICAgICJtb3ZsICUl -ZWJ4LDQoJSVlYXgpXG5cdCIKLQkgICAgIm1vdmwgJSVlY3gsOCglJWVheClcblx0IgotCSAgICAi -bW92bCAlJWVkeCwxMiglJWVheClcblx0IgotCSAgICAibW92bCAlJWVzaSwxNiglJWVheClcblx0 -IgotCSAgICAibW92bCAlJWVkaSwyMCglJWVheClcblx0IgotCSAgICAicG9wbCAlJWVkeFxuXHQi -Ci0JICAgICJtb3ZsICUlZWR4LDAoJSVlYXgpXG5cdCIKLQkgICAgImxhaGZcblx0IgotCSAgICAi -c2hybCAkOCwlJWVheFxuXHQiCi0JICAgICJhbmRsICQxLCUlZWF4XG4iCi0JICAgIDogIj1hIihy -YykKLQkgICAgOiAgICAiYSIocmVncykKLQkgICAgOiAgICAiJWVieCIsICIlZWN4IiwgIiVlZHgi -LCAiJWVzaSIsICIlZWRpIiwgIm1lbW9yeSIpOwotI2VuZGlmCi0JaWYgKHJjICE9IDAgfHwgKHJl -Z3MtPmVheCAmIDB4ZmZmZikgPT0gMHhmZmZmIHx8IHJlZ3MtPmVheCA9PSBlYXgpCi0JCXJjID0g -LUVJTlZBTDsKLQotb3V0OgotCXNldF9jcHVzX2FsbG93ZWRfcHRyKGN1cnJlbnQsIG9sZF9tYXNr -KTsKLQlmcmVlX2NwdW1hc2tfdmFyKG9sZF9tYXNrKTsKLQlyZXR1cm4gcmM7Ci19Ci0KLS8qCi0g -KiBSZWFkIHRoZSBGbiBrZXkgc3RhdHVzLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZm5fc3Rh -dHVzKHZvaWQpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0ZO -X1NUQVRVUywgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0oJnJlZ3MpOwotCWlmIChyYyA8 -IDApCi0JCXJldHVybiByYzsKLQotCXN3aXRjaCAoKHJlZ3MuZWF4ID4+IEk4S19GTl9TSElGVCkg -JiBJOEtfRk5fTUFTSykgewotCWNhc2UgSThLX0ZOX1VQOgotCQlyZXR1cm4gSThLX1ZPTF9VUDsK -LQljYXNlIEk4S19GTl9ET1dOOgotCQlyZXR1cm4gSThLX1ZPTF9ET1dOOwotCWNhc2UgSThLX0ZO -X01VVEU6Ci0JCXJldHVybiBJOEtfVk9MX01VVEU7Ci0JZGVmYXVsdDoKLQkJcmV0dXJuIDA7Ci0J -fQotfQotCi0vKgotICogUmVhZCB0aGUgcG93ZXIgc3RhdHVzLgotICovCi1zdGF0aWMgaW50IGk4 -a19nZXRfcG93ZXJfc3RhdHVzKHZvaWQpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5l -YXggPSBJOEtfU01NX1BPV0VSX1NUQVRVUywgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0o -JnJlZ3MpOwotCWlmIChyYyA8IDApCi0JCXJldHVybiByYzsKLQotCXJldHVybiAocmVncy5lYXgg -JiAweGZmKSA9PSBJOEtfUE9XRVJfQUMgPyBJOEtfQUMgOiBJOEtfQkFUVEVSWTsKLX0KLQotLyoK -LSAqIFJlYWQgdGhlIGZhbiBzdGF0dXMuCi0gKi8KLXN0YXRpYyBpbnQgaThrX2dldF9mYW5fc3Rh -dHVzKGludCBmYW4pCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01N -X0dFVF9GQU4sIH07Ci0KLQlyZWdzLmVieCA9IGZhbiAmIDB4ZmY7Ci0JcmV0dXJuIGk4a19zbW0o -JnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Ci19Ci0KLS8qCi0gKiBSZWFkIHRoZSBmYW4gc3Bl -ZWQgaW4gUlBNLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZmFuX3NwZWVkKGludCBmYW4pCi17 -Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9TUEVFRCwgfTsK -LQotCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKLQlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IChy -ZWdzLmVheCAmIDB4ZmZmZikgKiBpOGtfZmFuX211bHQ7Ci19Ci0KLS8qCi0gKiBSZWFkIHRoZSBm -YW4gdHlwZS4KLSAqLwotc3RhdGljIGludCBpOGtfZ2V0X2Zhbl90eXBlKGludCBmYW4pCi17Ci0J -c3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9GQU5fVFlQRSwgfTsK -LQotCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKLQlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IHJl -Z3MuZWF4ICYgMHhmZjsKLX0KLQotLyoKLSAqIFJlYWQgdGhlIGZhbiBub21pbmFsIHJwbSBmb3Ig -c3BlY2lmaWMgZmFuIHNwZWVkLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZmFuX25vbWluYWxf -c3BlZWQoaW50IGZhbiwgaW50IHNwZWVkKQotewotCXN0cnVjdCBzbW1fcmVncyByZWdzID0geyAu -ZWF4ID0gSThLX1NNTV9HRVRfTk9NX1NQRUVELCB9OwotCi0JcmVncy5lYnggPSAoZmFuICYgMHhm -ZikgfCAoc3BlZWQgPDwgOCk7Ci0JcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiAocmVncy5lYXgg -JiAweGZmZmYpICogaThrX2Zhbl9tdWx0OwotfQotCi0vKgotICogU2V0IHRoZSBmYW4gc3BlZWQg -KG9mZiwgbG93LCBoaWdoKS4gUmV0dXJucyB0aGUgbmV3IGZhbiBzdGF0dXMuCi0gKi8KLXN0YXRp -YyBpbnQgaThrX3NldF9mYW4oaW50IGZhbiwgaW50IHNwZWVkKQotewotCXN0cnVjdCBzbW1fcmVn -cyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9TRVRfRkFOLCB9OwotCi0Jc3BlZWQgPSAoc3BlZWQg -PCAwKSA/IDAgOiAoKHNwZWVkID4gaThrX2Zhbl9tYXgpID8gaThrX2Zhbl9tYXggOiBzcGVlZCk7 -Ci0JcmVncy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwgOCk7Ci0KLQlyZXR1cm4gaThr -X3NtbSgmcmVncykgPyA6IGk4a19nZXRfZmFuX3N0YXR1cyhmYW4pOwotfQotCi1zdGF0aWMgaW50 -IGk4a19nZXRfdGVtcF90eXBlKGludCBzZW5zb3IpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3Mg -PSB7IC5lYXggPSBJOEtfU01NX0dFVF9URU1QX1RZUEUsIH07Ci0KLQlyZWdzLmVieCA9IHNlbnNv -ciAmIDB4ZmY7Ci0JcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Ci19 -Ci0KLS8qCi0gKiBSZWFkIHRoZSBjcHUgdGVtcGVyYXR1cmUuCi0gKi8KLXN0YXRpYyBpbnQgX2k4 -a19nZXRfdGVtcChpbnQgc2Vuc29yKQotewotCXN0cnVjdCBzbW1fcmVncyByZWdzID0gewotCQku -ZWF4ID0gSThLX1NNTV9HRVRfVEVNUCwKLQkJLmVieCA9IHNlbnNvciAmIDB4ZmYsCi0JfTsKLQot -CXJldHVybiBpOGtfc21tKCZyZWdzKSA/IDogcmVncy5lYXggJiAweGZmOwotfQotCi1zdGF0aWMg -aW50IGk4a19nZXRfdGVtcChpbnQgc2Vuc29yKQotewotCWludCB0ZW1wID0gX2k4a19nZXRfdGVt -cChzZW5zb3IpOwotCi0JLyoKLQkgKiBTb21ldGltZXMgdGhlIHRlbXBlcmF0dXJlIHNlbnNvciBy -ZXR1cm5zIDB4OTksIHdoaWNoIGlzIG91dCBvZiByYW5nZS4KLQkgKiBJbiB0aGlzIGNhc2Ugd2Ug -cmV0cnkgKG9uY2UpIGJlZm9yZSByZXR1cm5pbmcgYW4gZXJyb3IuCi0JICMgMTAwMzY1NTEzNyAw -MDAwMDA1OCAwMDAwNWE0YgotCSAjIDEwMDM2NTUxMzggMDAwMDAwOTkgMDAwMDNhODAgPC0tLSAw -eDk5ID0gMTUzIGRlZ3JlZXMKLQkgIyAxMDAzNjU1MTM5IDAwMDAwMDU0IDAwMDA1YzUyCi0JICov -Ci0JaWYgKHRlbXAgPT0gMHg5OSkgewotCQltc2xlZXAoMTAwKTsKLQkJdGVtcCA9IF9pOGtfZ2V0 -X3RlbXAoc2Vuc29yKTsKLQl9Ci0JLyoKLQkgKiBSZXR1cm4gLUVOT0RBVEEgZm9yIGFsbCBpbnZh -bGlkIHRlbXBlcmF0dXJlcy4KLQkgKgotCSAqIEtub3duIGluc3RhbmNlcyBhcmUgdGhlIDB4OTkg -dmFsdWUgYXMgc2VlbiBhYm92ZSBhcyB3ZWxsIGFzCi0JICogMHhjMSAoMTkzKSwgd2hpY2ggbWF5 -IGJlIHJldHVybmVkIHdoZW4gdHJ5aW5nIHRvIHJlYWQgdGhlIEdQVQotCSAqIHRlbXBlcmF0dXJl -IGlmIHRoZSBzeXN0ZW0gc3VwcG9ydHMgYSBHUFUgYW5kIGl0IGlzIGN1cnJlbnRseQotCSAqIHR1 -cm5lZCBvZmYuCi0JICovCi0JaWYgKHRlbXAgPiBJOEtfTUFYX1RFTVApCi0JCXJldHVybiAtRU5P -REFUQTsKLQotCXJldHVybiB0ZW1wOwotfQotCi1zdGF0aWMgaW50IGk4a19nZXRfZGVsbF9zaWdu -YXR1cmUoaW50IHJlcV9mbikKLXsKLQlzdHJ1Y3Qgc21tX3JlZ3MgcmVncyA9IHsgLmVheCA9IHJl -cV9mbiwgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0oJnJlZ3MpOwotCWlmIChyYyA8IDAp -Ci0JCXJldHVybiByYzsKLQotCXJldHVybiByZWdzLmVheCA9PSAxMTQ1NjUxNTI3ICYmIHJlZ3Mu -ZWR4ID09IDExNDUzOTIyMDQgPyAwIDogLTE7Ci19Ci0KLXN0YXRpYyBpbnQKLWk4a19pb2N0bF91 -bmxvY2tlZChzdHJ1Y3QgZmlsZSAqZnAsIHVuc2lnbmVkIGludCBjbWQsIHVuc2lnbmVkIGxvbmcg -YXJnKQotewotCWludCB2YWwgPSAwOwotCWludCBzcGVlZDsKLQl1bnNpZ25lZCBjaGFyIGJ1ZmZb -MTZdOwotCWludCBfX3VzZXIgKmFyZ3AgPSAoaW50IF9fdXNlciAqKWFyZzsKLQotCWlmICghYXJn -cCkKLQkJcmV0dXJuIC1FSU5WQUw7Ci0KLQlzd2l0Y2ggKGNtZCkgewotCWNhc2UgSThLX0JJT1Nf -VkVSU0lPTjoKLQkJdmFsID0gKGJpb3NfdmVyc2lvblswXSA8PCAxNikgfAotCQkJCShiaW9zX3Zl -cnNpb25bMV0gPDwgOCkgfCBiaW9zX3ZlcnNpb25bMl07Ci0JCWJyZWFrOwotCi0JY2FzZSBJOEtf -TUFDSElORV9JRDoKLQkJbWVtc2V0KGJ1ZmYsIDAsIDE2KTsKLQkJc3RybGNweShidWZmLCBpOGtf -Z2V0X2RtaV9kYXRhKERNSV9QUk9EVUNUX1NFUklBTCksCi0JCQlzaXplb2YoYnVmZikpOwotCQli -cmVhazsKLQotCWNhc2UgSThLX0ZOX1NUQVRVUzoKLQkJdmFsID0gaThrX2dldF9mbl9zdGF0dXMo -KTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19QT1dFUl9TVEFUVVM6Ci0JCXZhbCA9IGk4a19nZXRf -cG93ZXJfc3RhdHVzKCk7Ci0JCWJyZWFrOwotCi0JY2FzZSBJOEtfR0VUX1RFTVA6Ci0JCXZhbCA9 -IGk4a19nZXRfdGVtcCgwKTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19HRVRfU1BFRUQ6Ci0JCWlm -IChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2YoaW50KSkpCi0JCQlyZXR1cm4gLUVG -QVVMVDsKLQotCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zcGVlZCh2YWwpOwotCQlicmVhazsKLQotCWNh -c2UgSThLX0dFVF9GQU46Ci0JCWlmIChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2Yo -aW50KSkpCi0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zdGF0dXMo -dmFsKTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19TRVRfRkFOOgotCQlpZiAocmVzdHJpY3RlZCAm -JiAhY2FwYWJsZShDQVBfU1lTX0FETUlOKSkKLQkJCXJldHVybiAtRVBFUk07Ci0KLQkJaWYgKGNv -cHlfZnJvbV91c2VyKCZ2YWwsIGFyZ3AsIHNpemVvZihpbnQpKSkKLQkJCXJldHVybiAtRUZBVUxU -OwotCi0JCWlmIChjb3B5X2Zyb21fdXNlcigmc3BlZWQsIGFyZ3AgKyAxLCBzaXplb2YoaW50KSkp -Ci0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQl2YWwgPSBpOGtfc2V0X2Zhbih2YWwsIHNwZWVkKTsK -LQkJYnJlYWs7Ci0KLQlkZWZhdWx0OgotCQlyZXR1cm4gLUVJTlZBTDsKLQl9Ci0KLQlpZiAodmFs -IDwgMCkKLQkJcmV0dXJuIHZhbDsKLQotCXN3aXRjaCAoY21kKSB7Ci0JY2FzZSBJOEtfQklPU19W -RVJTSU9OOgotCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWwsIDQpKQotCQkJcmV0dXJuIC1F -RkFVTFQ7Ci0KLQkJYnJlYWs7Ci0JY2FzZSBJOEtfTUFDSElORV9JRDoKLQkJaWYgKGNvcHlfdG9f -dXNlcihhcmdwLCBidWZmLCAxNikpCi0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQlicmVhazsKLQlk -ZWZhdWx0OgotCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWwsIHNpemVvZihpbnQpKSkKLQkJ -CXJldHVybiAtRUZBVUxUOwotCi0JCWJyZWFrOwotCX0KLQotCXJldHVybiAwOwotfQotCi1zdGF0 -aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUgKmZwLCB1bnNpZ25lZCBpbnQgY21kLCB1bnNp -Z25lZCBsb25nIGFyZykKLXsKLQlsb25nIHJldDsKLQotCW11dGV4X2xvY2soJmk4a19tdXRleCk7 -Ci0JcmV0ID0gaThrX2lvY3RsX3VubG9ja2VkKGZwLCBjbWQsIGFyZyk7Ci0JbXV0ZXhfdW5sb2Nr -KCZpOGtfbXV0ZXgpOwotCi0JcmV0dXJuIHJldDsKLX0KLQotLyoKLSAqIFByaW50IHRoZSBpbmZv -cm1hdGlvbiBmb3IgL3Byb2MvaThrLgotICovCi1zdGF0aWMgaW50IGk4a19wcm9jX3Nob3coc3Ry -dWN0IHNlcV9maWxlICpzZXEsIHZvaWQgKm9mZnNldCkKLXsKLQlpbnQgZm5fa2V5LCBjcHVfdGVt -cCwgYWNfcG93ZXI7Ci0JaW50IGxlZnRfZmFuLCByaWdodF9mYW4sIGxlZnRfc3BlZWQsIHJpZ2h0 -X3NwZWVkOwotCi0JY3B1X3RlbXAJPSBpOGtfZ2V0X3RlbXAoMCk7CQkJLyogMTExMDAgwrVzICov -Ci0JbGVmdF9mYW4JPSBpOGtfZ2V0X2Zhbl9zdGF0dXMoSThLX0ZBTl9MRUZUKTsJLyogICA1ODAg -wrVzICovCi0JcmlnaHRfZmFuCT0gaThrX2dldF9mYW5fc3RhdHVzKEk4S19GQU5fUklHSFQpOwkv -KiAgIDU4MCDCtXMgKi8KLQlsZWZ0X3NwZWVkCT0gaThrX2dldF9mYW5fc3BlZWQoSThLX0ZBTl9M -RUZUKTsJLyogICA1ODAgwrVzICovCi0JcmlnaHRfc3BlZWQJPSBpOGtfZ2V0X2Zhbl9zcGVlZChJ -OEtfRkFOX1JJR0hUKTsJLyogICA1ODAgwrVzICovCi0JZm5fa2V5CQk9IGk4a19nZXRfZm5fc3Rh -dHVzKCk7CQkJLyogICA3NTAgwrVzICovCi0JaWYgKHBvd2VyX3N0YXR1cykKLQkJYWNfcG93ZXIg -PSBpOGtfZ2V0X3Bvd2VyX3N0YXR1cygpOwkJLyogMTQ3MDAgwrVzICovCi0JZWxzZQotCQlhY19w -b3dlciA9IC0xOwotCi0JLyoKLQkgKiBJbmZvOgotCSAqCi0JICogMSkgIEZvcm1hdCB2ZXJzaW9u -ICh0aGlzIHdpbGwgY2hhbmdlIGlmIGZvcm1hdCBjaGFuZ2VzKQotCSAqIDIpICBCSU9TIHZlcnNp -b24KLQkgKiAzKSAgQklPUyBtYWNoaW5lIElECi0JICogNCkgIENwdSB0ZW1wZXJhdHVyZQotCSAq -IDUpICBMZWZ0IGZhbiBzdGF0dXMKLQkgKiA2KSAgUmlnaHQgZmFuIHN0YXR1cwotCSAqIDcpICBM -ZWZ0IGZhbiBzcGVlZAotCSAqIDgpICBSaWdodCBmYW4gc3BlZWQKLQkgKiA5KSAgQUMgcG93ZXIK -LQkgKiAxMCkgRm4gS2V5IHN0YXR1cwotCSAqLwotCXJldHVybiBzZXFfcHJpbnRmKHNlcSwgIiVz -ICVzICVzICVkICVkICVkICVkICVkICVkICVkXG4iLAotCQkJICBJOEtfUFJPQ19GTVQsCi0JCQkg -IGJpb3NfdmVyc2lvbiwKLQkJCSAgaThrX2dldF9kbWlfZGF0YShETUlfUFJPRFVDVF9TRVJJQUwp -LAotCQkJICBjcHVfdGVtcCwKLQkJCSAgbGVmdF9mYW4sIHJpZ2h0X2ZhbiwgbGVmdF9zcGVlZCwg -cmlnaHRfc3BlZWQsCi0JCQkgIGFjX3Bvd2VyLCBmbl9rZXkpOwotfQotCi1zdGF0aWMgaW50IGk4 -a19vcGVuX2ZzKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpmaWxlKQotewotCXJl -dHVybiBzaW5nbGVfb3BlbihmaWxlLCBpOGtfcHJvY19zaG93LCBOVUxMKTsKLX0KLQotCi0vKgot -ICogSHdtb24gaW50ZXJmYWNlCi0gKi8KLQotc3RhdGljIHNzaXplX3QgaThrX2h3bW9uX3Nob3df -dGVtcF9sYWJlbChzdHJ1Y3QgZGV2aWNlICpkZXYsCi0JCQkJCSBzdHJ1Y3QgZGV2aWNlX2F0dHJp -YnV0ZSAqZGV2YXR0ciwKLQkJCQkJIGNoYXIgKmJ1ZikKLXsKLQlzdGF0aWMgY29uc3QgY2hhciAq -IGNvbnN0IGxhYmVsc1tdID0gewotCQkiQ1BVIiwKLQkJIkdQVSIsCi0JCSJTT0RJTU0iLAotCQki -T3RoZXIiLAotCQkiQW1iaWVudCIsCi0JCSJPdGhlciIsCi0JfTsKLQlpbnQgaW5kZXggPSB0b19z -ZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4OwotCWludCB0eXBlOwotCi0JdHlwZSA9IGk4 -a19nZXRfdGVtcF90eXBlKGluZGV4KTsKLQlpZiAodHlwZSA8IDApCi0JCXJldHVybiB0eXBlOwot -CWlmICh0eXBlID49IEFSUkFZX1NJWkUobGFiZWxzKSkKLQkJdHlwZSA9IEFSUkFZX1NJWkUobGFi -ZWxzKSAtIDE7Ci0JcmV0dXJuIHNwcmludGYoYnVmLCAiJXNcbiIsIGxhYmVsc1t0eXBlXSk7Ci19 -Ci0KLXN0YXRpYyBzc2l6ZV90IGk4a19od21vbl9zaG93X3RlbXAoc3RydWN0IGRldmljZSAqZGV2 -LAotCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZhdHRyLAotCQkJCSAgIGNoYXIg -KmJ1ZikKLXsKLQlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4 -OwotCWludCB0ZW1wOwotCi0JdGVtcCA9IGk4a19nZXRfdGVtcChpbmRleCk7Ci0JaWYgKHRlbXAg -PCAwKQotCQlyZXR1cm4gdGVtcDsKLQlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwgdGVtcCAq -IDEwMDApOwotfQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19mYW5fbGFiZWwoc3Ry -dWN0IGRldmljZSAqZGV2LAotCQkJCQlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwK -LQkJCQkJY2hhciAqYnVmKQotewotCXN0YXRpYyBjb25zdCBjaGFyICogY29uc3QgbGFiZWxzW10g -PSB7Ci0JCSJQcm9jZXNzb3IgRmFuIiwKLQkJIk1vdGhlcmJvYXJkIEZhbiIsCi0JCSJWaWRlbyBG -YW4iLAotCQkiUG93ZXIgU3VwcGx5IEZhbiIsCi0JCSJDaGlwc2V0IEZhbiIsCi0JCSJPdGhlciBG -YW4iLAotCX07Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRl -eDsKLQlib29sIGRvY2sgPSBmYWxzZTsKLQlpbnQgdHlwZTsKLQotCXR5cGUgPSBpOGtfZ2V0X2Zh -bl90eXBlKGluZGV4KTsKLQlpZiAodHlwZSA8IDApCi0JCXJldHVybiB0eXBlOwotCi0JaWYgKHR5 -cGUgJiAweDEwKSB7Ci0JCWRvY2sgPSB0cnVlOwotCQl0eXBlICY9IDB4MEY7Ci0JfQotCi0JaWYg -KHR5cGUgPj0gQVJSQVlfU0laRShsYWJlbHMpKQotCQl0eXBlID0gKEFSUkFZX1NJWkUobGFiZWxz -KSAtIDEpOwotCi0JcmV0dXJuIHNwcmludGYoYnVmLCAiJXMlc1xuIiwgKGRvY2sgPyAiRG9ja2lu -ZyAiIDogIiIpLCBsYWJlbHNbdHlwZV0pOwotfQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25f -c2hvd19mYW4oc3RydWN0IGRldmljZSAqZGV2LAotCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1 -dGUgKmRldmF0dHIsCi0JCQkJICBjaGFyICpidWYpCi17Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29y -X2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsKLQlpbnQgZmFuX3NwZWVkOwotCi0JZmFuX3NwZWVk -ID0gaThrX2dldF9mYW5fc3BlZWQoaW5kZXgpOwotCWlmIChmYW5fc3BlZWQgPCAwKQotCQlyZXR1 -cm4gZmFuX3NwZWVkOwotCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCBmYW5fc3BlZWQpOwot -fQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19wd20oc3RydWN0IGRldmljZSAqZGV2 -LAotCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCi0JCQkJICBjaGFyICpi -dWYpCi17Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsK -LQlpbnQgc3RhdHVzOwotCi0Jc3RhdHVzID0gaThrX2dldF9mYW5fc3RhdHVzKGluZGV4KTsKLQlp -ZiAoc3RhdHVzIDwgMCkKLQkJcmV0dXJuIC1FSU87Ci0JcmV0dXJuIHNwcmludGYoYnVmLCAiJWRc -biIsIGNsYW1wX3ZhbChzdGF0dXMgKiBpOGtfcHdtX211bHQsIDAsIDI1NSkpOwotfQotCi1zdGF0 -aWMgc3NpemVfdCBpOGtfaHdtb25fc2V0X3B3bShzdHJ1Y3QgZGV2aWNlICpkZXYsCi0JCQkJIHN0 -cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLAotCQkJCSBjb25zdCBjaGFyICpidWYsIHNpemVf -dCBjb3VudCkKLXsKLQlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoYXR0ciktPmluZGV4 -OwotCXVuc2lnbmVkIGxvbmcgdmFsOwotCWludCBlcnI7Ci0KLQllcnIgPSBrc3RydG91bChidWYs -IDEwLCAmdmFsKTsKLQlpZiAoZXJyKQotCQlyZXR1cm4gZXJyOwotCXZhbCA9IGNsYW1wX3ZhbChE -SVZfUk9VTkRfQ0xPU0VTVCh2YWwsIGk4a19wd21fbXVsdCksIDAsIGk4a19mYW5fbWF4KTsKLQot -CW11dGV4X2xvY2soJmk4a19tdXRleCk7Ci0JZXJyID0gaThrX3NldF9mYW4oaW5kZXgsIHZhbCk7 -Ci0JbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOwotCi0JcmV0dXJuIGVyciA8IDAgPyAtRUlPIDog -Y291bnQ7Ci19Ci0KLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfaW5wdXQsIFNfSVJV -R08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDApOwotc3RhdGljIFNFTlNPUl9ERVZJQ0Vf -QVRUUih0ZW1wMV9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbCwgTlVM -TCwKLQkJCSAgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX2lucHV0LCBTX0lS -VUdPLCBpOGtfaHdtb25fc2hvd190ZW1wLCBOVUxMLCAxKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNF -X0FUVFIodGVtcDJfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXBfbGFiZWwsIE5V -TEwsCi0JCQkgIDEpOwotc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19pbnB1dCwgU19J -UlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcCwgTlVMTCwgMik7Ci1zdGF0aWMgU0VOU09SX0RFVklD -RV9BVFRSKHRlbXAzX2xhYmVsLCBTX0lSVUdPLCBpOGtfaHdtb25fc2hvd190ZW1wX2xhYmVsLCBO -VUxMLAotCQkJICAyKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDRfaW5wdXQsIFNf -SVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDMpOwotc3RhdGljIFNFTlNPUl9ERVZJ -Q0VfQVRUUih0ZW1wNF9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbCwg -TlVMTCwKLQkJCSAgMyk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKGZhbjFfaW5wdXQsIFNf -SVJVR08sIGk4a19od21vbl9zaG93X2ZhbiwgTlVMTCwgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklD -RV9BVFRSKGZhbjFfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9zaG93X2Zhbl9sYWJlbCwgTlVM -TCwKLQkJCSAgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHB3bTEsIFNfSVJVR08gfCBT -X0lXVVNSLCBpOGtfaHdtb25fc2hvd19wd20sCi0JCQkgIGk4a19od21vbl9zZXRfcHdtLCAwKTsK -LXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFuMl9pbnB1dCwgU19JUlVHTywgaThrX2h3bW9u -X3Nob3dfZmFuLCBOVUxMLAotCQkJICAxKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFu -Ml9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuX2xhYmVsLCBOVUxMLAotCQkJICAx -KTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIocHdtMiwgU19JUlVHTyB8IFNfSVdVU1IsIGk4 -a19od21vbl9zaG93X3B3bSwKLQkJCSAgaThrX2h3bW9uX3NldF9wd20sIDEpOwotCi1zdGF0aWMg -c3RydWN0IGF0dHJpYnV0ZSAqaThrX2F0dHJzW10gPSB7Ci0JJnNlbnNvcl9kZXZfYXR0cl90ZW1w -MV9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAwICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9s -YWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAxICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMl9pbnB1 -dC5kZXZfYXR0ci5hdHRyLAkvKiAyICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMl9sYWJlbC5k -ZXZfYXR0ci5hdHRyLAkvKiAzICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wM19pbnB1dC5kZXZf -YXR0ci5hdHRyLAkvKiA0ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wM19sYWJlbC5kZXZfYXR0 -ci5hdHRyLAkvKiA1ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9pbnB1dC5kZXZfYXR0ci5h -dHRyLAkvKiA2ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9sYWJlbC5kZXZfYXR0ci5hdHRy -LAkvKiA3ICovCi0JJnNlbnNvcl9kZXZfYXR0cl9mYW4xX2lucHV0LmRldl9hdHRyLmF0dHIsCS8q -IDggKi8KLQkmc2Vuc29yX2Rldl9hdHRyX2ZhbjFfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyogOSAq -LwotCSZzZW5zb3JfZGV2X2F0dHJfcHdtMS5kZXZfYXR0ci5hdHRyLAkJLyogMTAgKi8KLQkmc2Vu -c29yX2Rldl9hdHRyX2ZhbjJfaW5wdXQuZGV2X2F0dHIuYXR0ciwJLyogMTEgKi8KLQkmc2Vuc29y -X2Rldl9hdHRyX2ZhbjJfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyogMTIgKi8KLQkmc2Vuc29yX2Rl -dl9hdHRyX3B3bTIuZGV2X2F0dHIuYXR0ciwJCS8qIDEzICovCi0JTlVMTAotfTsKLQotc3RhdGlj -IHVtb2RlX3QgaThrX2lzX3Zpc2libGUoc3RydWN0IGtvYmplY3QgKmtvYmosIHN0cnVjdCBhdHRy -aWJ1dGUgKmF0dHIsCi0JCQkgICAgICBpbnQgaW5kZXgpCi17Ci0JaWYgKGluZGV4ID49IDAgJiYg -aW5kZXggPD0gMSAmJgotCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RF -TVAxKSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDIgJiYgaW5kZXggPD0gMyAmJgotCSAg -ICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RFTVAyKSkKLQkJcmV0dXJuIDA7 -Ci0JaWYgKGluZGV4ID49IDQgJiYgaW5kZXggPD0gNSAmJgotCSAgICAhKGk4a19od21vbl9mbGFn -cyAmIEk4S19IV01PTl9IQVZFX1RFTVAzKSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDYg -JiYgaW5kZXggPD0gNyAmJgotCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZF -X1RFTVA0KSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDggJiYgaW5kZXggPD0gMTAgJiYK -LQkgICAgIShpOGtfaHdtb25fZmxhZ3MgJiBJOEtfSFdNT05fSEFWRV9GQU4xKSkKLQkJcmV0dXJu -IDA7Ci0JaWYgKGluZGV4ID49IDExICYmIGluZGV4IDw9IDEzICYmCi0JICAgICEoaThrX2h3bW9u -X2ZsYWdzICYgSThLX0hXTU9OX0hBVkVfRkFOMikpCi0JCXJldHVybiAwOwotCi0JcmV0dXJuIGF0 -dHItPm1vZGU7Ci19Ci0KLXN0YXRpYyBjb25zdCBzdHJ1Y3QgYXR0cmlidXRlX2dyb3VwIGk4a19n -cm91cCA9IHsKLQkuYXR0cnMgPSBpOGtfYXR0cnMsCi0JLmlzX3Zpc2libGUgPSBpOGtfaXNfdmlz -aWJsZSwKLX07Ci1fX0FUVFJJQlVURV9HUk9VUFMoaThrKTsKLQotc3RhdGljIGludCBfX2luaXQg -aThrX2luaXRfaHdtb24odm9pZCkKLXsKLQlpbnQgZXJyOwotCi0JaThrX2h3bW9uX2ZsYWdzID0g -MDsKLQotCS8qIENQVSB0ZW1wZXJhdHVyZSBhdHRyaWJ1dGVzLCBpZiB0ZW1wZXJhdHVyZSB0eXBl -IGlzIE9LICovCi0JZXJyID0gaThrX2dldF90ZW1wX3R5cGUoMCk7Ci0JaWYgKGVyciA+PSAwKQot -CQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfVEVNUDE7Ci0JLyogY2hlY2sgZm9y -IGFkZGl0aW9uYWwgdGVtcGVyYXR1cmUgc2Vuc29ycyAqLwotCWVyciA9IGk4a19nZXRfdGVtcF90 -eXBlKDEpOwotCWlmIChlcnIgPj0gMCkKLQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9I -QVZFX1RFTVAyOwotCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDIpOwotCWlmIChlcnIgPj0gMCkK -LQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVAzOwotCWVyciA9IGk4a19n -ZXRfdGVtcF90eXBlKDMpOwotCWlmIChlcnIgPj0gMCkKLQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4 -S19IV01PTl9IQVZFX1RFTVA0OwotCi0JLyogRmlyc3QgZmFuIGF0dHJpYnV0ZXMsIGlmIGZhbiB0 -eXBlIGlzIE9LICovCi0JZXJyID0gaThrX2dldF9mYW5fdHlwZSgwKTsKLQlpZiAoZXJyID49IDAp -Ci0JCWk4a19od21vbl9mbGFncyB8PSBJOEtfSFdNT05fSEFWRV9GQU4xOwotCi0JLyogU2Vjb25k -IGZhbiBhdHRyaWJ1dGVzLCBpZiBmYW4gdHlwZSBpcyBPSyAqLwotCWVyciA9IGk4a19nZXRfZmFu -X3R5cGUoMSk7Ci0JaWYgKGVyciA+PSAwKQotCQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9O -X0hBVkVfRkFOMjsKLQotCWk4a19od21vbl9kZXYgPSBod21vbl9kZXZpY2VfcmVnaXN0ZXJfd2l0 -aF9ncm91cHMoTlVMTCwgImk4ayIsIE5VTEwsCi0JCQkJCQkJICBpOGtfZ3JvdXBzKTsKLQlpZiAo -SVNfRVJSKGk4a19od21vbl9kZXYpKSB7Ci0JCWVyciA9IFBUUl9FUlIoaThrX2h3bW9uX2Rldik7 -Ci0JCWk4a19od21vbl9kZXYgPSBOVUxMOwotCQlwcl9lcnIoImh3bW9uIHJlZ2lzdHJhdGlvbiBm -YWlsZWQgKCVkKVxuIiwgZXJyKTsKLQkJcmV0dXJuIGVycjsKLQl9Ci0JcmV0dXJuIDA7Ci19Ci0K -LXN0cnVjdCBpOGtfY29uZmlnX2RhdGEgewotCXVpbnQgZmFuX211bHQ7Ci0JdWludCBmYW5fbWF4 -OwotfTsKLQotZW51bSBpOGtfY29uZmlncyB7Ci0JREVMTF9MQVRJVFVERV9ENTIwLAotCURFTExf -UFJFQ0lTSU9OXzQ5MCwKLQlERUxMX1NUVURJTywKLQlERUxMX1hQUywKLX07Ci0KLXN0YXRpYyBj -b25zdCBzdHJ1Y3QgaThrX2NvbmZpZ19kYXRhIGk4a19jb25maWdfZGF0YVtdID0gewotCVtERUxM -X0xBVElUVURFX0Q1MjBdID0gewotCQkuZmFuX211bHQgPSAxLAotCQkuZmFuX21heCA9IEk4S19G -QU5fVFVSQk8sCi0JfSwKLQlbREVMTF9QUkVDSVNJT05fNDkwXSA9IHsKLQkJLmZhbl9tdWx0ID0g -MSwKLQkJLmZhbl9tYXggPSBJOEtfRkFOX1RVUkJPLAotCX0sCi0JW0RFTExfU1RVRElPXSA9IHsK -LQkJLmZhbl9tdWx0ID0gMSwKLQkJLmZhbl9tYXggPSBJOEtfRkFOX0hJR0gsCi0JfSwKLQlbREVM -TF9YUFNdID0gewotCQkuZmFuX211bHQgPSAxLAotCQkuZmFuX21heCA9IEk4S19GQU5fSElHSCwK -LQl9LAotfTsKLQotc3RhdGljIHN0cnVjdCBkbWlfc3lzdGVtX2lkIGk4a19kbWlfdGFibGVbXSBf -X2luaXRkYXRhID0gewotCXsKLQkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24iLAotCQkubWF0Y2hl -cyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKLQkJ -CURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiSW5zcGlyb24iKSwKLQkJfSwKLQl9LAotCXsK -LQkJLmlkZW50ID0gIkRlbGwgTGF0aXR1ZGUiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRD -SChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKLQkJCURNSV9NQVRDSChETUlfUFJP -RFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKLQkJfSwKLQl9LAotCXsKLQkJLmlkZW50ID0gIkRlbGwg -SW5zcGlyb24gMiIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9S -LCAiRGVsbCBJbmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIkluc3Bpcm9u -IiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJEZWxsIExhdGl0dWRlIEQ1MjAiLAotCQku -bWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAot -CQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJMYXRpdHVkZSBENTIwIiksCi0JCX0sCi0J -CS5kcml2ZXJfZGF0YSA9ICh2b2lkICopJmk4a19jb25maWdfZGF0YVtERUxMX0xBVElUVURFX0Q1 -MjBdLAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBMYXRpdHVkZSAyIiwKLQkJLm1hdGNoZXMg -PSB7Ci0JCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKLQkJCURNSV9N -QVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKLQkJfSwKLQl9LAotCXsJLyogVUsg -SW5zcGlyb24gNjQwMCAgKi8KLQkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24gMyIsCi0JCS5tYXRj -aGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCi0JCQlE -TUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1NMDYxIiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5p -ZGVudCA9ICJEZWxsIEluc3Bpcm9uIDMiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChE -TUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05B -TUUsICJNUDA2MSIpLAotCQl9LAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBQcmVjaXNpb24g -NDkwIiwKLQkJLm1hdGNoZXMgPSB7Ci0JCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxs -IEluYy4iKSwKLQkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLAotCQkJCSAgIlByZWNpc2lv -biBXb3JrU3RhdGlvbiA0OTAiKSwKLQkJfSwKLQkJLmRyaXZlcl9kYXRhID0gKHZvaWQgKikmaThr -X2NvbmZpZ19kYXRhW0RFTExfUFJFQ0lTSU9OXzQ5MF0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJE -ZWxsIFByZWNpc2lvbiIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVO -RE9SLCAiRGVsbCBJbmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlByZWNp -c2lvbiIpLAotCQl9LAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBWb3N0cm8iLAotCQkubWF0 -Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJ -RE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJWb3N0cm8iKSwKLQkJfSwKLQl9LAotCXsKLQkJ -LmlkZW50ID0gIkRlbGwgWFBTNDIxIiwKLQkJLm1hdGNoZXMgPSB7Ci0JCQlETUlfTUFUQ0goRE1J -X1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKLQkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1F -LCAiWFBTIEw0MjFYIiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJEZWxsIFN0dWRpbyIs -Ci0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMu -IiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlN0dWRpbyIpLAotCQl9LAotCQku -ZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9TVFVESU9dLAotCX0s -Ci0JewotCQkuaWRlbnQgPSAiRGVsbCBYUFMgMTMiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9N -QVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJRE1JX01BVENIKERNSV9QUk9E -VUNUX05BTUUsICJYUFMxMyIpLAotCQl9LAotCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtf -Y29uZmlnX2RhdGFbREVMTF9YUFNdLAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBYUFMgTTE0 -MCIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJ -bmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1YQzA1MSIpLAotCQl9LAot -CQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9YUFNdLAotCX0s -Ci0JeyB9Ci19OwotCi1NT0RVTEVfREVWSUNFX1RBQkxFKGRtaSwgaThrX2RtaV90YWJsZSk7Ci0K -LS8qCi0gKiBQcm9iZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgc3VwcG9ydGVkIGxhcHRvcC4KLSAq -Lwotc3RhdGljIGludCBfX2luaXQgaThrX3Byb2JlKHZvaWQpCi17Ci0JY29uc3Qgc3RydWN0IGRt -aV9zeXN0ZW1faWQgKmlkOwotCWludCBmYW4sIHJldDsKLQotCS8qCi0JICogR2V0IERNSSBpbmZv -cm1hdGlvbgotCSAqLwotCWlmICghZG1pX2NoZWNrX3N5c3RlbShpOGtfZG1pX3RhYmxlKSkgewot -CQlpZiAoIWlnbm9yZV9kbWkgJiYgIWZvcmNlKQotCQkJcmV0dXJuIC1FTk9ERVY7Ci0KLQkJcHJf -aW5mbygibm90IHJ1bm5pbmcgb24gYSBzdXBwb3J0ZWQgRGVsbCBzeXN0ZW0uXG4iKTsKLQkJcHJf -aW5mbygidmVuZG9yPSVzLCBtb2RlbD0lcywgdmVyc2lvbj0lc1xuIiwKLQkJCWk4a19nZXRfZG1p -X2RhdGEoRE1JX1NZU19WRU5ET1IpLAotCQkJaThrX2dldF9kbWlfZGF0YShETUlfUFJPRFVDVF9O -QU1FKSwKLQkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX0JJT1NfVkVSU0lPTikpOwotCX0KLQotCXN0 -cmxjcHkoYmlvc192ZXJzaW9uLCBpOGtfZ2V0X2RtaV9kYXRhKERNSV9CSU9TX1ZFUlNJT04pLAot -CQlzaXplb2YoYmlvc192ZXJzaW9uKSk7Ci0KLQkvKgotCSAqIEdldCBTTU0gRGVsbCBzaWduYXR1 -cmUKLQkgKi8KLQlpZiAoaThrX2dldF9kZWxsX3NpZ25hdHVyZShJOEtfU01NX0dFVF9ERUxMX1NJ -RzEpICYmCi0JICAgIGk4a19nZXRfZGVsbF9zaWduYXR1cmUoSThLX1NNTV9HRVRfREVMTF9TSUcy -KSkgewotCQlwcl9lcnIoInVuYWJsZSB0byBnZXQgU01NIERlbGwgc2lnbmF0dXJlXG4iKTsKLQkJ -aWYgKCFmb3JjZSkKLQkJCXJldHVybiAtRU5PREVWOwotCX0KLQotCS8qCi0JICogU2V0IGZhbiBt -dWx0aXBsaWVyIGFuZCBtYXhpbWFsIGZhbiBzcGVlZCBmcm9tIGRtaSBjb25maWcKLQkgKiBWYWx1 -ZXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbWV0ZXJzIG92ZXJyaWRlIHZhbHVlcyBmcm9tIGRt -aQotCSAqLwotCWlkID0gZG1pX2ZpcnN0X21hdGNoKGk4a19kbWlfdGFibGUpOwotCWlmIChpZCAm -JiBpZC0+ZHJpdmVyX2RhdGEpIHsKLQkJY29uc3Qgc3RydWN0IGk4a19jb25maWdfZGF0YSAqY29u -ZiA9IGlkLT5kcml2ZXJfZGF0YTsKLQkJaWYgKCFmYW5fbXVsdCAmJiBjb25mLT5mYW5fbXVsdCkK -LQkJCWZhbl9tdWx0ID0gY29uZi0+ZmFuX211bHQ7Ci0JCWlmICghZmFuX21heCAmJiBjb25mLT5m -YW5fbWF4KQotCQkJZmFuX21heCA9IGNvbmYtPmZhbl9tYXg7Ci0JfQotCi0JaThrX2Zhbl9tYXgg -PSBmYW5fbWF4ID8gOiBJOEtfRkFOX0hJR0g7CS8qIE11c3Qgbm90IGJlIDAgKi8KLQlpOGtfcHdt -X211bHQgPSBESVZfUk9VTkRfVVAoMjU1LCBpOGtfZmFuX21heCk7Ci0KLQlpZiAoIWZhbl9tdWx0 -KSB7Ci0JCS8qCi0JCSAqIEF1dG9kZXRlY3QgZmFuIG11bHRpcGxpZXIgYmFzZWQgb24gbm9taW5h -bCBycG0KLQkJICogSWYgZmFuIHJlcG9ydHMgcnBtIHZhbHVlIHRvbyBoaWdoIHRoZW4gc2V0IG11 -bHRpcGxpZXIgdG8gMQotCQkgKi8KLQkJZm9yIChmYW4gPSAwOyBmYW4gPCAyOyArK2Zhbikgewot -CQkJcmV0ID0gaThrX2dldF9mYW5fbm9taW5hbF9zcGVlZChmYW4sIGk4a19mYW5fbWF4KTsKLQkJ -CWlmIChyZXQgPCAwKQotCQkJCWNvbnRpbnVlOwotCQkJaWYgKHJldCA+IEk4S19GQU5fTUFYX1JQ -TSkKLQkJCQlpOGtfZmFuX211bHQgPSAxOwotCQkJYnJlYWs7Ci0JCX0KLQl9IGVsc2UgewotCQkv -KiBGYW4gbXVsdGlwbGllciB3YXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbSBvciBpbiBkbWkg -Ki8KLQkJaThrX2Zhbl9tdWx0ID0gZmFuX211bHQ7Ci0JfQotCi0JcmV0dXJuIDA7Ci19Ci0KLXN0 -YXRpYyBpbnQgX19pbml0IGk4a19pbml0KHZvaWQpCi17Ci0Jc3RydWN0IHByb2NfZGlyX2VudHJ5 -ICpwcm9jX2k4azsKLQlpbnQgZXJyOwotCi0JLyogQXJlIHdlIHJ1bm5pbmcgb24gYW4gc3VwcG9y -dGVkIGxhcHRvcD8gKi8KLQlpZiAoaThrX3Byb2JlKCkpCi0JCXJldHVybiAtRU5PREVWOwotCi0J -LyogUmVnaXN0ZXIgdGhlIHByb2MgZW50cnkgKi8KLQlwcm9jX2k4ayA9IHByb2NfY3JlYXRlKCJp -OGsiLCAwLCBOVUxMLCAmaThrX2ZvcHMpOwotCWlmICghcHJvY19pOGspCi0JCXJldHVybiAtRU5P -RU5UOwotCi0JZXJyID0gaThrX2luaXRfaHdtb24oKTsKLQlpZiAoZXJyKQotCQlnb3RvIGV4aXRf -cmVtb3ZlX3Byb2M7Ci0KLQlyZXR1cm4gMDsKLQotIGV4aXRfcmVtb3ZlX3Byb2M6Ci0JcmVtb3Zl -X3Byb2NfZW50cnkoImk4ayIsIE5VTEwpOwotCXJldHVybiBlcnI7Ci19Ci0KLXN0YXRpYyB2b2lk -IF9fZXhpdCBpOGtfZXhpdCh2b2lkKQotewotCWh3bW9uX2RldmljZV91bnJlZ2lzdGVyKGk4a19o -d21vbl9kZXYpOwotCXJlbW92ZV9wcm9jX2VudHJ5KCJpOGsiLCBOVUxMKTsKLX0KLQotbW9kdWxl -X2luaXQoaThrX2luaXQpOwotbW9kdWxlX2V4aXQoaThrX2V4aXQpOwpkaWZmIC0tZ2l0IGEvZHJp -dmVycy9od21vbi9NYWtlZmlsZSBiL2RyaXZlcnMvaHdtb24vTWFrZWZpbGUKaW5kZXggNmM5NDE0 -Ny4uMWMzZTQ1OCAxMDA2NDQKLS0tIGEvZHJpdmVycy9od21vbi9NYWtlZmlsZQorKysgYi9kcml2 -ZXJzL2h3bW9uL01ha2VmaWxlCkBAIC0xNTUsNiArMTU1LDcgQEAgb2JqLSQoQ09ORklHX1NFTlNP -UlNfVzgzTDc4NVRTKQkrPSB3ODNsNzg1dHMubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfVzgzTDc4 -Nk5HKQkrPSB3ODNsNzg2bmcubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfV004MzFYKQkrPSB3bTgz -MXgtaHdtb24ubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfV004MzUwKQkrPSB3bTgzNTAtaHdtb24u -bworb2JqLSQoQ09ORklHX0k4SykJCSs9IGRlbGwtc21tLWh3bW9uLm8KIAogb2JqLSQoQ09ORklH -X1BNQlVTKQkJKz0gcG1idXMvCiAKZGlmZiAtLWdpdCBhL2RyaXZlcnMvaHdtb24vZGVsbC1zbW0t -aHdtb24uYyBiL2RyaXZlcnMvaHdtb24vZGVsbC1zbW0taHdtb24uYwpuZXcgZmlsZSBtb2RlIDEw -MDY0NAppbmRleCAwMDAwMDAwLi4yYjA0ZTRmCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9o -d21vbi9kZWxsLXNtbS1od21vbi5jCkBAIC0wLDAgKzEsMTAwNyBAQAorLyoKKyAqIGRlbGwtc21t -LWh3bW9uLmMgLS0gTGludXggZHJpdmVyIGZvciBhY2Nlc3NpbmcgdGhlIFNNTSBCSU9TIG9uIERl -bGwgbGFwdG9wcy4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMDEgIE1hc3NpbW8gRGFsIFpvdHRv -IDxkekBkZWJpYW4ub3JnPgorICoKKyAqIEh3bW9uIGludGVncmF0aW9uOgorICogQ29weXJpZ2h0 -IChDKSAyMDExICBKZWFuIERlbHZhcmUgPGpkZWx2YXJlQHN1c2UuZGU+CisgKiBDb3B5cmlnaHQg -KEMpIDIwMTMsIDIwMTQgIEd1ZW50ZXIgUm9lY2sgPGxpbnV4QHJvZWNrLXVzLm5ldD4KKyAqIENv -cHlyaWdodCAoQykgMjAxNCwgMjAxNSAgUGFsaSBSb2jDoXIgPHBhbGkucm9oYXJAZ21haWwuY29t -PgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJp -YnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgKiB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBH -ZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUKKyAqIEZyZWUgU29mdHdh -cmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMiwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkK -KyAqIGxhdGVyIHZlcnNpb24uCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGlu -IHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dAorICogV0lUSE9VVCBBTlkgV0FS -UkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICogTUVSQ0hBTlRB -QklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUK -KyAqIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAqLworCisjZGVm -aW5lIHByX2ZtdChmbXQpIEtCVUlMRF9NT0ROQU1FICI6ICIgZm10CisKKyNpbmNsdWRlIDxsaW51 -eC9kZWxheS5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1ZGUgPGxpbnV4L3R5 -cGVzLmg+CisjaW5jbHVkZSA8bGludXgvaW5pdC5oPgorI2luY2x1ZGUgPGxpbnV4L3Byb2NfZnMu -aD4KKyNpbmNsdWRlIDxsaW51eC9zZXFfZmlsZS5oPgorI2luY2x1ZGUgPGxpbnV4L2RtaS5oPgor -I2luY2x1ZGUgPGxpbnV4L2NhcGFiaWxpdHkuaD4KKyNpbmNsdWRlIDxsaW51eC9tdXRleC5oPgor -I2luY2x1ZGUgPGxpbnV4L2h3bW9uLmg+CisjaW5jbHVkZSA8bGludXgvaHdtb24tc3lzZnMuaD4K -KyNpbmNsdWRlIDxsaW51eC91YWNjZXNzLmg+CisjaW5jbHVkZSA8bGludXgvaW8uaD4KKyNpbmNs -dWRlIDxsaW51eC9zY2hlZC5oPgorCisjaW5jbHVkZSA8bGludXgvaThrLmg+CisKKyNkZWZpbmUg -SThLX1NNTV9GTl9TVEFUVVMJMHgwMDI1CisjZGVmaW5lIEk4S19TTU1fUE9XRVJfU1RBVFVTCTB4 -MDA2OQorI2RlZmluZSBJOEtfU01NX1NFVF9GQU4JCTB4MDFhMworI2RlZmluZSBJOEtfU01NX0dF -VF9GQU4JCTB4MDBhMworI2RlZmluZSBJOEtfU01NX0dFVF9TUEVFRAkweDAyYTMKKyNkZWZpbmUg -SThLX1NNTV9HRVRfRkFOX1RZUEUJMHgwM2EzCisjZGVmaW5lIEk4S19TTU1fR0VUX05PTV9TUEVF -RAkweDA0YTMKKyNkZWZpbmUgSThLX1NNTV9HRVRfVEVNUAkweDEwYTMKKyNkZWZpbmUgSThLX1NN -TV9HRVRfVEVNUF9UWVBFCTB4MTFhMworI2RlZmluZSBJOEtfU01NX0dFVF9ERUxMX1NJRzEJMHhm -ZWEzCisjZGVmaW5lIEk4S19TTU1fR0VUX0RFTExfU0lHMgkweGZmYTMKKworI2RlZmluZSBJOEtf -RkFOX01VTFQJCTMwCisjZGVmaW5lIEk4S19GQU5fTUFYX1JQTQkJMzAwMDAKKyNkZWZpbmUgSThL -X01BWF9URU1QCQkxMjcKKworI2RlZmluZSBJOEtfRk5fTk9ORQkJMHgwMAorI2RlZmluZSBJOEtf -Rk5fVVAJCTB4MDEKKyNkZWZpbmUgSThLX0ZOX0RPV04JCTB4MDIKKyNkZWZpbmUgSThLX0ZOX01V -VEUJCTB4MDQKKyNkZWZpbmUgSThLX0ZOX01BU0sJCTB4MDcKKyNkZWZpbmUgSThLX0ZOX1NISUZU -CQk4CisKKyNkZWZpbmUgSThLX1BPV0VSX0FDCQkweDA1CisjZGVmaW5lIEk4S19QT1dFUl9CQVRU -RVJZCTB4MDEKKworc3RhdGljIERFRklORV9NVVRFWChpOGtfbXV0ZXgpOworc3RhdGljIGNoYXIg -Ymlvc192ZXJzaW9uWzRdOworc3RhdGljIHN0cnVjdCBkZXZpY2UgKmk4a19od21vbl9kZXY7Citz -dGF0aWMgdTMyIGk4a19od21vbl9mbGFnczsKK3N0YXRpYyB1aW50IGk4a19mYW5fbXVsdCA9IEk4 -S19GQU5fTVVMVDsKK3N0YXRpYyB1aW50IGk4a19wd21fbXVsdDsKK3N0YXRpYyB1aW50IGk4a19m -YW5fbWF4ID0gSThLX0ZBTl9ISUdIOworCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVAxCSgx -IDw8IDApCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVAyCSgxIDw8IDEpCisjZGVmaW5lIEk4 -S19IV01PTl9IQVZFX1RFTVAzCSgxIDw8IDIpCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVA0 -CSgxIDw8IDMpCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX0ZBTjEJKDEgPDwgNCkKKyNkZWZpbmUg -SThLX0hXTU9OX0hBVkVfRkFOMgkoMSA8PCA1KQorCitNT0RVTEVfQVVUSE9SKCJNYXNzaW1vIERh -bCBab3R0byAoZHpAZGViaWFuLm9yZykiKTsKK01PRFVMRV9BVVRIT1IoIlBhbGkgUm9ow6FyIDxw -YWxpLnJvaGFyQGdtYWlsLmNvbT4iKTsKK01PRFVMRV9ERVNDUklQVElPTigiRHJpdmVyIGZvciBh -Y2Nlc3NpbmcgU01NIEJJT1Mgb24gRGVsbCBsYXB0b3BzIik7CitNT0RVTEVfTElDRU5TRSgiR1BM -Iik7CitNT0RVTEVfQUxJQVMoImk4ayIpOworCitzdGF0aWMgYm9vbCBmb3JjZTsKK21vZHVsZV9w -YXJhbShmb3JjZSwgYm9vbCwgMCk7CitNT0RVTEVfUEFSTV9ERVNDKGZvcmNlLCAiRm9yY2UgbG9h -ZGluZyB3aXRob3V0IGNoZWNraW5nIGZvciBzdXBwb3J0ZWQgbW9kZWxzIik7CisKK3N0YXRpYyBi -b29sIGlnbm9yZV9kbWk7Cittb2R1bGVfcGFyYW0oaWdub3JlX2RtaSwgYm9vbCwgMCk7CitNT0RV -TEVfUEFSTV9ERVNDKGlnbm9yZV9kbWksICJDb250aW51ZSBwcm9iaW5nIGhhcmR3YXJlIGV2ZW4g -aWYgRE1JIGRhdGEgZG9lcyBub3QgbWF0Y2giKTsKKworc3RhdGljIGJvb2wgcmVzdHJpY3RlZDsK -K21vZHVsZV9wYXJhbShyZXN0cmljdGVkLCBib29sLCAwKTsKK01PRFVMRV9QQVJNX0RFU0MocmVz -dHJpY3RlZCwgIkFsbG93IGZhbiBjb250cm9sIGlmIFNZU19BRE1JTiBjYXBhYmlsaXR5IHNldCIp -OworCitzdGF0aWMgYm9vbCBwb3dlcl9zdGF0dXM7Cittb2R1bGVfcGFyYW0ocG93ZXJfc3RhdHVz -LCBib29sLCAwNjAwKTsKK01PRFVMRV9QQVJNX0RFU0MocG93ZXJfc3RhdHVzLCAiUmVwb3J0IHBv -d2VyIHN0YXR1cyBpbiAvcHJvYy9pOGsiKTsKKworc3RhdGljIHVpbnQgZmFuX211bHQ7Cittb2R1 -bGVfcGFyYW0oZmFuX211bHQsIHVpbnQsIDApOworTU9EVUxFX1BBUk1fREVTQyhmYW5fbXVsdCwg -IkZhY3RvciB0byBtdWx0aXBseSBmYW4gc3BlZWQgd2l0aCAoZGVmYXVsdDogYXV0b2RldGVjdCki -KTsKKworc3RhdGljIHVpbnQgZmFuX21heDsKK21vZHVsZV9wYXJhbShmYW5fbWF4LCB1aW50LCAw -KTsKK01PRFVMRV9QQVJNX0RFU0MoZmFuX21heCwgIk1heGltdW0gY29uZmlndXJhYmxlIGZhbiBz -cGVlZCAoZGVmYXVsdDogYXV0b2RldGVjdCkiKTsKKworc3RhdGljIGludCBpOGtfb3Blbl9mcyhz -dHJ1Y3QgaW5vZGUgKmlub2RlLCBzdHJ1Y3QgZmlsZSAqZmlsZSk7CitzdGF0aWMgbG9uZyBpOGtf -aW9jdGwoc3RydWN0IGZpbGUgKiwgdW5zaWduZWQgaW50LCB1bnNpZ25lZCBsb25nKTsKKworc3Rh -dGljIGNvbnN0IHN0cnVjdCBmaWxlX29wZXJhdGlvbnMgaThrX2ZvcHMgPSB7CisJLm93bmVyCQk9 -IFRISVNfTU9EVUxFLAorCS5vcGVuCQk9IGk4a19vcGVuX2ZzLAorCS5yZWFkCQk9IHNlcV9yZWFk -LAorCS5sbHNlZWsJCT0gc2VxX2xzZWVrLAorCS5yZWxlYXNlCT0gc2luZ2xlX3JlbGVhc2UsCisJ -LnVubG9ja2VkX2lvY3RsCT0gaThrX2lvY3RsLAorfTsKKworc3RydWN0IHNtbV9yZWdzIHsKKwl1 -bnNpZ25lZCBpbnQgZWF4OworCXVuc2lnbmVkIGludCBlYnggX19wYWNrZWQ7CisJdW5zaWduZWQg -aW50IGVjeCBfX3BhY2tlZDsKKwl1bnNpZ25lZCBpbnQgZWR4IF9fcGFja2VkOworCXVuc2lnbmVk -IGludCBlc2kgX19wYWNrZWQ7CisJdW5zaWduZWQgaW50IGVkaSBfX3BhY2tlZDsKK307CisKK3N0 -YXRpYyBpbmxpbmUgY29uc3QgY2hhciAqaThrX2dldF9kbWlfZGF0YShpbnQgZmllbGQpCit7CisJ -Y29uc3QgY2hhciAqZG1pX2RhdGEgPSBkbWlfZ2V0X3N5c3RlbV9pbmZvKGZpZWxkKTsKKworCXJl -dHVybiBkbWlfZGF0YSAmJiAqZG1pX2RhdGEgPyBkbWlfZGF0YSA6ICI/IjsKK30KKworLyoKKyAq -IENhbGwgdGhlIFN5c3RlbSBNYW5hZ2VtZW50IE1vZGUgQklPUy4gQ29kZSBwcm92aWRlZCBieSBK -b25hdGhhbiBCdXp6YXJkLgorICovCitzdGF0aWMgaW50IGk4a19zbW0oc3RydWN0IHNtbV9yZWdz -ICpyZWdzKQoreworCWludCByYzsKKwlpbnQgZWF4ID0gcmVncy0+ZWF4OworCWNwdW1hc2tfdmFy -X3Qgb2xkX21hc2s7CisKKwkvKiBTTU0gcmVxdWlyZXMgQ1BVIDAgKi8KKwlpZiAoIWFsbG9jX2Nw -dW1hc2tfdmFyKCZvbGRfbWFzaywgR0ZQX0tFUk5FTCkpCisJCXJldHVybiAtRU5PTUVNOworCWNw -dW1hc2tfY29weShvbGRfbWFzaywgJmN1cnJlbnQtPmNwdXNfYWxsb3dlZCk7CisJcmMgPSBzZXRf -Y3B1c19hbGxvd2VkX3B0cihjdXJyZW50LCBjcHVtYXNrX29mKDApKTsKKwlpZiAocmMpCisJCWdv -dG8gb3V0OworCWlmIChzbXBfcHJvY2Vzc29yX2lkKCkgIT0gMCkgeworCQlyYyA9IC1FQlVTWTsK -KwkJZ290byBvdXQ7CisJfQorCisjaWYgZGVmaW5lZChDT05GSUdfWDg2XzY0KQorCWFzbSB2b2xh -dGlsZSgicHVzaHEgJSVyYXhcblx0IgorCQkibW92bCAwKCUlcmF4KSwlJWVkeFxuXHQiCisJCSJw -dXNocSAlJXJkeFxuXHQiCisJCSJtb3ZsIDQoJSVyYXgpLCUlZWJ4XG5cdCIKKwkJIm1vdmwgOCgl -JXJheCksJSVlY3hcblx0IgorCQkibW92bCAxMiglJXJheCksJSVlZHhcblx0IgorCQkibW92bCAx -NiglJXJheCksJSVlc2lcblx0IgorCQkibW92bCAyMCglJXJheCksJSVlZGlcblx0IgorCQkicG9w -cSAlJXJheFxuXHQiCisJCSJvdXQgJSVhbCwkMHhiMlxuXHQiCisJCSJvdXQgJSVhbCwkMHg4NFxu -XHQiCisJCSJ4Y2hncSAlJXJheCwoJSVyc3ApXG5cdCIKKwkJIm1vdmwgJSVlYngsNCglJXJheClc -blx0IgorCQkibW92bCAlJWVjeCw4KCUlcmF4KVxuXHQiCisJCSJtb3ZsICUlZWR4LDEyKCUlcmF4 -KVxuXHQiCisJCSJtb3ZsICUlZXNpLDE2KCUlcmF4KVxuXHQiCisJCSJtb3ZsICUlZWRpLDIwKCUl -cmF4KVxuXHQiCisJCSJwb3BxICUlcmR4XG5cdCIKKwkJIm1vdmwgJSVlZHgsMCglJXJheClcblx0 -IgorCQkicHVzaGZxXG5cdCIKKwkJInBvcHEgJSVyYXhcblx0IgorCQkiYW5kbCAkMSwlJWVheFxu -IgorCQk6ICI9YSIocmMpCisJCTogICAgImEiKHJlZ3MpCisJCTogICAgIiVlYngiLCAiJWVjeCIs -ICIlZWR4IiwgIiVlc2kiLCAiJWVkaSIsICJtZW1vcnkiKTsKKyNlbHNlCisJYXNtIHZvbGF0aWxl -KCJwdXNobCAlJWVheFxuXHQiCisJICAgICJtb3ZsIDAoJSVlYXgpLCUlZWR4XG5cdCIKKwkgICAg -InB1c2ggJSVlZHhcblx0IgorCSAgICAibW92bCA0KCUlZWF4KSwlJWVieFxuXHQiCisJICAgICJt -b3ZsIDgoJSVlYXgpLCUlZWN4XG5cdCIKKwkgICAgIm1vdmwgMTIoJSVlYXgpLCUlZWR4XG5cdCIK -KwkgICAgIm1vdmwgMTYoJSVlYXgpLCUlZXNpXG5cdCIKKwkgICAgIm1vdmwgMjAoJSVlYXgpLCUl -ZWRpXG5cdCIKKwkgICAgInBvcGwgJSVlYXhcblx0IgorCSAgICAib3V0ICUlYWwsJDB4YjJcblx0 -IgorCSAgICAib3V0ICUlYWwsJDB4ODRcblx0IgorCSAgICAieGNoZ2wgJSVlYXgsKCUlZXNwKVxu -XHQiCisJICAgICJtb3ZsICUlZWJ4LDQoJSVlYXgpXG5cdCIKKwkgICAgIm1vdmwgJSVlY3gsOCgl -JWVheClcblx0IgorCSAgICAibW92bCAlJWVkeCwxMiglJWVheClcblx0IgorCSAgICAibW92bCAl -JWVzaSwxNiglJWVheClcblx0IgorCSAgICAibW92bCAlJWVkaSwyMCglJWVheClcblx0IgorCSAg -ICAicG9wbCAlJWVkeFxuXHQiCisJICAgICJtb3ZsICUlZWR4LDAoJSVlYXgpXG5cdCIKKwkgICAg -ImxhaGZcblx0IgorCSAgICAic2hybCAkOCwlJWVheFxuXHQiCisJICAgICJhbmRsICQxLCUlZWF4 -XG4iCisJICAgIDogIj1hIihyYykKKwkgICAgOiAgICAiYSIocmVncykKKwkgICAgOiAgICAiJWVi -eCIsICIlZWN4IiwgIiVlZHgiLCAiJWVzaSIsICIlZWRpIiwgIm1lbW9yeSIpOworI2VuZGlmCisJ -aWYgKHJjICE9IDAgfHwgKHJlZ3MtPmVheCAmIDB4ZmZmZikgPT0gMHhmZmZmIHx8IHJlZ3MtPmVh -eCA9PSBlYXgpCisJCXJjID0gLUVJTlZBTDsKKworb3V0OgorCXNldF9jcHVzX2FsbG93ZWRfcHRy -KGN1cnJlbnQsIG9sZF9tYXNrKTsKKwlmcmVlX2NwdW1hc2tfdmFyKG9sZF9tYXNrKTsKKwlyZXR1 -cm4gcmM7Cit9CisKKy8qCisgKiBSZWFkIHRoZSBGbiBrZXkgc3RhdHVzLgorICovCitzdGF0aWMg -aW50IGk4a19nZXRfZm5fc3RhdHVzKHZvaWQpCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7 -IC5lYXggPSBJOEtfU01NX0ZOX1NUQVRVUywgfTsKKwlpbnQgcmM7CisKKwlyYyA9IGk4a19zbW0o -JnJlZ3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKworCXN3aXRjaCAoKHJlZ3MuZWF4 -ID4+IEk4S19GTl9TSElGVCkgJiBJOEtfRk5fTUFTSykgeworCWNhc2UgSThLX0ZOX1VQOgorCQly -ZXR1cm4gSThLX1ZPTF9VUDsKKwljYXNlIEk4S19GTl9ET1dOOgorCQlyZXR1cm4gSThLX1ZPTF9E -T1dOOworCWNhc2UgSThLX0ZOX01VVEU6CisJCXJldHVybiBJOEtfVk9MX01VVEU7CisJZGVmYXVs -dDoKKwkJcmV0dXJuIDA7CisJfQorfQorCisvKgorICogUmVhZCB0aGUgcG93ZXIgc3RhdHVzLgor -ICovCitzdGF0aWMgaW50IGk4a19nZXRfcG93ZXJfc3RhdHVzKHZvaWQpCit7CisJc3RydWN0IHNt -bV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX1BPV0VSX1NUQVRVUywgfTsKKwlpbnQgcmM7 -CisKKwlyYyA9IGk4a19zbW0oJnJlZ3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKwor -CXJldHVybiAocmVncy5lYXggJiAweGZmKSA9PSBJOEtfUE9XRVJfQUMgPyBJOEtfQUMgOiBJOEtf -QkFUVEVSWTsKK30KKworLyoKKyAqIFJlYWQgdGhlIGZhbiBzdGF0dXMuCisgKi8KK3N0YXRpYyBp -bnQgaThrX2dldF9mYW5fc3RhdHVzKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3Mg -PSB7IC5lYXggPSBJOEtfU01NX0dFVF9GQU4sIH07CisKKwlyZWdzLmVieCA9IGZhbiAmIDB4ZmY7 -CisJcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Cit9CisKKy8qCisg -KiBSZWFkIHRoZSBmYW4gc3BlZWQgaW4gUlBNLgorICovCitzdGF0aWMgaW50IGk4a19nZXRfZmFu -X3NwZWVkKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtf -U01NX0dFVF9TUEVFRCwgfTsKKworCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKKwlyZXR1cm4gaThr -X3NtbSgmcmVncykgPyA6IChyZWdzLmVheCAmIDB4ZmZmZikgKiBpOGtfZmFuX211bHQ7Cit9CisK -Ky8qCisgKiBSZWFkIHRoZSBmYW4gdHlwZS4KKyAqLworc3RhdGljIGludCBpOGtfZ2V0X2Zhbl90 -eXBlKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01N -X0dFVF9GQU5fVFlQRSwgfTsKKworCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKKwlyZXR1cm4gaThr -X3NtbSgmcmVncykgPyA6IHJlZ3MuZWF4ICYgMHhmZjsKK30KKworLyoKKyAqIFJlYWQgdGhlIGZh -biBub21pbmFsIHJwbSBmb3Igc3BlY2lmaWMgZmFuIHNwZWVkLgorICovCitzdGF0aWMgaW50IGk4 -a19nZXRfZmFuX25vbWluYWxfc3BlZWQoaW50IGZhbiwgaW50IHNwZWVkKQoreworCXN0cnVjdCBz -bW1fcmVncyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9HRVRfTk9NX1NQRUVELCB9OworCisJcmVn -cy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwgOCk7CisJcmV0dXJuIGk4a19zbW0oJnJl -Z3MpID8gOiAocmVncy5lYXggJiAweGZmZmYpICogaThrX2Zhbl9tdWx0OworfQorCisvKgorICog -U2V0IHRoZSBmYW4gc3BlZWQgKG9mZiwgbG93LCBoaWdoKS4gUmV0dXJucyB0aGUgbmV3IGZhbiBz -dGF0dXMuCisgKi8KK3N0YXRpYyBpbnQgaThrX3NldF9mYW4oaW50IGZhbiwgaW50IHNwZWVkKQor -eworCXN0cnVjdCBzbW1fcmVncyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9TRVRfRkFOLCB9Owor -CisJc3BlZWQgPSAoc3BlZWQgPCAwKSA/IDAgOiAoKHNwZWVkID4gaThrX2Zhbl9tYXgpID8gaThr -X2Zhbl9tYXggOiBzcGVlZCk7CisJcmVncy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwg -OCk7CisKKwlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IGk4a19nZXRfZmFuX3N0YXR1cyhmYW4p -OworfQorCitzdGF0aWMgaW50IGk4a19nZXRfdGVtcF90eXBlKGludCBzZW5zb3IpCit7CisJc3Ry -dWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9URU1QX1RZUEUsIH07CisK -KwlyZWdzLmVieCA9IHNlbnNvciAmIDB4ZmY7CisJcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiBy -ZWdzLmVheCAmIDB4ZmY7Cit9CisKKy8qCisgKiBSZWFkIHRoZSBjcHUgdGVtcGVyYXR1cmUuCisg -Ki8KK3N0YXRpYyBpbnQgX2k4a19nZXRfdGVtcChpbnQgc2Vuc29yKQoreworCXN0cnVjdCBzbW1f -cmVncyByZWdzID0geworCQkuZWF4ID0gSThLX1NNTV9HRVRfVEVNUCwKKwkJLmVieCA9IHNlbnNv -ciAmIDB4ZmYsCisJfTsKKworCXJldHVybiBpOGtfc21tKCZyZWdzKSA/IDogcmVncy5lYXggJiAw -eGZmOworfQorCitzdGF0aWMgaW50IGk4a19nZXRfdGVtcChpbnQgc2Vuc29yKQoreworCWludCB0 -ZW1wID0gX2k4a19nZXRfdGVtcChzZW5zb3IpOworCisJLyoKKwkgKiBTb21ldGltZXMgdGhlIHRl -bXBlcmF0dXJlIHNlbnNvciByZXR1cm5zIDB4OTksIHdoaWNoIGlzIG91dCBvZiByYW5nZS4KKwkg -KiBJbiB0aGlzIGNhc2Ugd2UgcmV0cnkgKG9uY2UpIGJlZm9yZSByZXR1cm5pbmcgYW4gZXJyb3Iu -CisJICMgMTAwMzY1NTEzNyAwMDAwMDA1OCAwMDAwNWE0YgorCSAjIDEwMDM2NTUxMzggMDAwMDAw -OTkgMDAwMDNhODAgPC0tLSAweDk5ID0gMTUzIGRlZ3JlZXMKKwkgIyAxMDAzNjU1MTM5IDAwMDAw -MDU0IDAwMDA1YzUyCisJICovCisJaWYgKHRlbXAgPT0gMHg5OSkgeworCQltc2xlZXAoMTAwKTsK -KwkJdGVtcCA9IF9pOGtfZ2V0X3RlbXAoc2Vuc29yKTsKKwl9CisJLyoKKwkgKiBSZXR1cm4gLUVO -T0RBVEEgZm9yIGFsbCBpbnZhbGlkIHRlbXBlcmF0dXJlcy4KKwkgKgorCSAqIEtub3duIGluc3Rh -bmNlcyBhcmUgdGhlIDB4OTkgdmFsdWUgYXMgc2VlbiBhYm92ZSBhcyB3ZWxsIGFzCisJICogMHhj -MSAoMTkzKSwgd2hpY2ggbWF5IGJlIHJldHVybmVkIHdoZW4gdHJ5aW5nIHRvIHJlYWQgdGhlIEdQ -VQorCSAqIHRlbXBlcmF0dXJlIGlmIHRoZSBzeXN0ZW0gc3VwcG9ydHMgYSBHUFUgYW5kIGl0IGlz -IGN1cnJlbnRseQorCSAqIHR1cm5lZCBvZmYuCisJICovCisJaWYgKHRlbXAgPiBJOEtfTUFYX1RF -TVApCisJCXJldHVybiAtRU5PREFUQTsKKworCXJldHVybiB0ZW1wOworfQorCitzdGF0aWMgaW50 -IGk4a19nZXRfZGVsbF9zaWduYXR1cmUoaW50IHJlcV9mbikKK3sKKwlzdHJ1Y3Qgc21tX3JlZ3Mg -cmVncyA9IHsgLmVheCA9IHJlcV9mbiwgfTsKKwlpbnQgcmM7CisKKwlyYyA9IGk4a19zbW0oJnJl -Z3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKworCXJldHVybiByZWdzLmVheCA9PSAx -MTQ1NjUxNTI3ICYmIHJlZ3MuZWR4ID09IDExNDUzOTIyMDQgPyAwIDogLTE7Cit9CisKK3N0YXRp -YyBpbnQKK2k4a19pb2N0bF91bmxvY2tlZChzdHJ1Y3QgZmlsZSAqZnAsIHVuc2lnbmVkIGludCBj -bWQsIHVuc2lnbmVkIGxvbmcgYXJnKQoreworCWludCB2YWwgPSAwOworCWludCBzcGVlZDsKKwl1 -bnNpZ25lZCBjaGFyIGJ1ZmZbMTZdOworCWludCBfX3VzZXIgKmFyZ3AgPSAoaW50IF9fdXNlciAq -KWFyZzsKKworCWlmICghYXJncCkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlzd2l0Y2ggKGNtZCkg -eworCWNhc2UgSThLX0JJT1NfVkVSU0lPTjoKKwkJdmFsID0gKGJpb3NfdmVyc2lvblswXSA8PCAx -NikgfAorCQkJCShiaW9zX3ZlcnNpb25bMV0gPDwgOCkgfCBiaW9zX3ZlcnNpb25bMl07CisJCWJy -ZWFrOworCisJY2FzZSBJOEtfTUFDSElORV9JRDoKKwkJbWVtc2V0KGJ1ZmYsIDAsIDE2KTsKKwkJ -c3RybGNweShidWZmLCBpOGtfZ2V0X2RtaV9kYXRhKERNSV9QUk9EVUNUX1NFUklBTCksCisJCQlz -aXplb2YoYnVmZikpOworCQlicmVhazsKKworCWNhc2UgSThLX0ZOX1NUQVRVUzoKKwkJdmFsID0g -aThrX2dldF9mbl9zdGF0dXMoKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4S19QT1dFUl9TVEFUVVM6 -CisJCXZhbCA9IGk4a19nZXRfcG93ZXJfc3RhdHVzKCk7CisJCWJyZWFrOworCisJY2FzZSBJOEtf -R0VUX1RFTVA6CisJCXZhbCA9IGk4a19nZXRfdGVtcCgwKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4 -S19HRVRfU1BFRUQ6CisJCWlmIChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2YoaW50 -KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zcGVlZCh2YWwp -OworCQlicmVhazsKKworCWNhc2UgSThLX0dFVF9GQU46CisJCWlmIChjb3B5X2Zyb21fdXNlcigm -dmFsLCBhcmdwLCBzaXplb2YoaW50KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBp -OGtfZ2V0X2Zhbl9zdGF0dXModmFsKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4S19TRVRfRkFOOgor -CQlpZiAocmVzdHJpY3RlZCAmJiAhY2FwYWJsZShDQVBfU1lTX0FETUlOKSkKKwkJCXJldHVybiAt -RVBFUk07CisKKwkJaWYgKGNvcHlfZnJvbV91c2VyKCZ2YWwsIGFyZ3AsIHNpemVvZihpbnQpKSkK -KwkJCXJldHVybiAtRUZBVUxUOworCisJCWlmIChjb3B5X2Zyb21fdXNlcigmc3BlZWQsIGFyZ3Ag -KyAxLCBzaXplb2YoaW50KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBpOGtfc2V0 -X2Zhbih2YWwsIHNwZWVkKTsKKwkJYnJlYWs7CisKKwlkZWZhdWx0OgorCQlyZXR1cm4gLUVJTlZB -TDsKKwl9CisKKwlpZiAodmFsIDwgMCkKKwkJcmV0dXJuIHZhbDsKKworCXN3aXRjaCAoY21kKSB7 -CisJY2FzZSBJOEtfQklPU19WRVJTSU9OOgorCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWws -IDQpKQorCQkJcmV0dXJuIC1FRkFVTFQ7CisKKwkJYnJlYWs7CisJY2FzZSBJOEtfTUFDSElORV9J -RDoKKwkJaWYgKGNvcHlfdG9fdXNlcihhcmdwLCBidWZmLCAxNikpCisJCQlyZXR1cm4gLUVGQVVM -VDsKKworCQlicmVhazsKKwlkZWZhdWx0OgorCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWws -IHNpemVvZihpbnQpKSkKKwkJCXJldHVybiAtRUZBVUxUOworCisJCWJyZWFrOworCX0KKworCXJl -dHVybiAwOworfQorCitzdGF0aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUgKmZwLCB1bnNp -Z25lZCBpbnQgY21kLCB1bnNpZ25lZCBsb25nIGFyZykKK3sKKwlsb25nIHJldDsKKworCW11dGV4 -X2xvY2soJmk4a19tdXRleCk7CisJcmV0ID0gaThrX2lvY3RsX3VubG9ja2VkKGZwLCBjbWQsIGFy -Zyk7CisJbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOworCisJcmV0dXJuIHJldDsKK30KKworLyoK -KyAqIFByaW50IHRoZSBpbmZvcm1hdGlvbiBmb3IgL3Byb2MvaThrLgorICovCitzdGF0aWMgaW50 -IGk4a19wcm9jX3Nob3coc3RydWN0IHNlcV9maWxlICpzZXEsIHZvaWQgKm9mZnNldCkKK3sKKwlp -bnQgZm5fa2V5LCBjcHVfdGVtcCwgYWNfcG93ZXI7CisJaW50IGxlZnRfZmFuLCByaWdodF9mYW4s -IGxlZnRfc3BlZWQsIHJpZ2h0X3NwZWVkOworCisJY3B1X3RlbXAJPSBpOGtfZ2V0X3RlbXAoMCk7 -CQkJLyogMTExMDAgwrVzICovCisJbGVmdF9mYW4JPSBpOGtfZ2V0X2Zhbl9zdGF0dXMoSThLX0ZB -Tl9MRUZUKTsJLyogICA1ODAgwrVzICovCisJcmlnaHRfZmFuCT0gaThrX2dldF9mYW5fc3RhdHVz -KEk4S19GQU5fUklHSFQpOwkvKiAgIDU4MCDCtXMgKi8KKwlsZWZ0X3NwZWVkCT0gaThrX2dldF9m -YW5fc3BlZWQoSThLX0ZBTl9MRUZUKTsJLyogICA1ODAgwrVzICovCisJcmlnaHRfc3BlZWQJPSBp -OGtfZ2V0X2Zhbl9zcGVlZChJOEtfRkFOX1JJR0hUKTsJLyogICA1ODAgwrVzICovCisJZm5fa2V5 -CQk9IGk4a19nZXRfZm5fc3RhdHVzKCk7CQkJLyogICA3NTAgwrVzICovCisJaWYgKHBvd2VyX3N0 -YXR1cykKKwkJYWNfcG93ZXIgPSBpOGtfZ2V0X3Bvd2VyX3N0YXR1cygpOwkJLyogMTQ3MDAgwrVz -ICovCisJZWxzZQorCQlhY19wb3dlciA9IC0xOworCisJLyoKKwkgKiBJbmZvOgorCSAqCisJICog -MSkgIEZvcm1hdCB2ZXJzaW9uICh0aGlzIHdpbGwgY2hhbmdlIGlmIGZvcm1hdCBjaGFuZ2VzKQor -CSAqIDIpICBCSU9TIHZlcnNpb24KKwkgKiAzKSAgQklPUyBtYWNoaW5lIElECisJICogNCkgIENw -dSB0ZW1wZXJhdHVyZQorCSAqIDUpICBMZWZ0IGZhbiBzdGF0dXMKKwkgKiA2KSAgUmlnaHQgZmFu -IHN0YXR1cworCSAqIDcpICBMZWZ0IGZhbiBzcGVlZAorCSAqIDgpICBSaWdodCBmYW4gc3BlZWQK -KwkgKiA5KSAgQUMgcG93ZXIKKwkgKiAxMCkgRm4gS2V5IHN0YXR1cworCSAqLworCXJldHVybiBz -ZXFfcHJpbnRmKHNlcSwgIiVzICVzICVzICVkICVkICVkICVkICVkICVkICVkXG4iLAorCQkJICBJ -OEtfUFJPQ19GTVQsCisJCQkgIGJpb3NfdmVyc2lvbiwKKwkJCSAgaThrX2dldF9kbWlfZGF0YShE -TUlfUFJPRFVDVF9TRVJJQUwpLAorCQkJICBjcHVfdGVtcCwKKwkJCSAgbGVmdF9mYW4sIHJpZ2h0 -X2ZhbiwgbGVmdF9zcGVlZCwgcmlnaHRfc3BlZWQsCisJCQkgIGFjX3Bvd2VyLCBmbl9rZXkpOwor -fQorCitzdGF0aWMgaW50IGk4a19vcGVuX2ZzKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBm -aWxlICpmaWxlKQoreworCXJldHVybiBzaW5nbGVfb3BlbihmaWxlLCBpOGtfcHJvY19zaG93LCBO -VUxMKTsKK30KKworCisvKgorICogSHdtb24gaW50ZXJmYWNlCisgKi8KKworc3RhdGljIHNzaXpl -X3QgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbChzdHJ1Y3QgZGV2aWNlICpkZXYsCisJCQkJCSBz -dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwKKwkJCQkJIGNoYXIgKmJ1ZikKK3sKKwlz -dGF0aWMgY29uc3QgY2hhciAqIGNvbnN0IGxhYmVsc1tdID0geworCQkiQ1BVIiwKKwkJIkdQVSIs -CisJCSJTT0RJTU0iLAorCQkiT3RoZXIiLAorCQkiQW1iaWVudCIsCisJCSJPdGhlciIsCisJfTsK -KwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4OworCWludCB0 -eXBlOworCisJdHlwZSA9IGk4a19nZXRfdGVtcF90eXBlKGluZGV4KTsKKwlpZiAodHlwZSA8IDAp -CisJCXJldHVybiB0eXBlOworCWlmICh0eXBlID49IEFSUkFZX1NJWkUobGFiZWxzKSkKKwkJdHlw -ZSA9IEFSUkFZX1NJWkUobGFiZWxzKSAtIDE7CisJcmV0dXJuIHNwcmludGYoYnVmLCAiJXNcbiIs -IGxhYmVsc1t0eXBlXSk7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGk4a19od21vbl9zaG93X3RlbXAo -c3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZh -dHRyLAorCQkJCSAgIGNoYXIgKmJ1ZikKK3sKKwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0 -dHIoZGV2YXR0ciktPmluZGV4OworCWludCB0ZW1wOworCisJdGVtcCA9IGk4a19nZXRfdGVtcChp -bmRleCk7CisJaWYgKHRlbXAgPCAwKQorCQlyZXR1cm4gdGVtcDsKKwlyZXR1cm4gc3ByaW50Zihi -dWYsICIlZFxuIiwgdGVtcCAqIDEwMDApOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25f -c2hvd19mYW5fbGFiZWwoc3RydWN0IGRldmljZSAqZGV2LAorCQkJCQlzdHJ1Y3QgZGV2aWNlX2F0 -dHJpYnV0ZSAqZGV2YXR0ciwKKwkJCQkJY2hhciAqYnVmKQoreworCXN0YXRpYyBjb25zdCBjaGFy -ICogY29uc3QgbGFiZWxzW10gPSB7CisJCSJQcm9jZXNzb3IgRmFuIiwKKwkJIk1vdGhlcmJvYXJk -IEZhbiIsCisJCSJWaWRlbyBGYW4iLAorCQkiUG93ZXIgU3VwcGx5IEZhbiIsCisJCSJDaGlwc2V0 -IEZhbiIsCisJCSJPdGhlciBGYW4iLAorCX07CisJaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9h -dHRyKGRldmF0dHIpLT5pbmRleDsKKwlib29sIGRvY2sgPSBmYWxzZTsKKwlpbnQgdHlwZTsKKwor -CXR5cGUgPSBpOGtfZ2V0X2Zhbl90eXBlKGluZGV4KTsKKwlpZiAodHlwZSA8IDApCisJCXJldHVy -biB0eXBlOworCisJaWYgKHR5cGUgJiAweDEwKSB7CisJCWRvY2sgPSB0cnVlOworCQl0eXBlICY9 -IDB4MEY7CisJfQorCisJaWYgKHR5cGUgPj0gQVJSQVlfU0laRShsYWJlbHMpKQorCQl0eXBlID0g -KEFSUkFZX1NJWkUobGFiZWxzKSAtIDEpOworCisJcmV0dXJuIHNwcmludGYoYnVmLCAiJXMlc1xu -IiwgKGRvY2sgPyAiRG9ja2luZyAiIDogIiIpLCBsYWJlbHNbdHlwZV0pOworfQorCitzdGF0aWMg -c3NpemVfdCBpOGtfaHdtb25fc2hvd19mYW4oc3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgc3Ry -dWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCisJCQkJICBjaGFyICpidWYpCit7CisJaW50 -IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsKKwlpbnQgZmFuX3Nw -ZWVkOworCisJZmFuX3NwZWVkID0gaThrX2dldF9mYW5fc3BlZWQoaW5kZXgpOworCWlmIChmYW5f -c3BlZWQgPCAwKQorCQlyZXR1cm4gZmFuX3NwZWVkOworCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVk -XG4iLCBmYW5fc3BlZWQpOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19wd20o -c3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0 -dHIsCisJCQkJICBjaGFyICpidWYpCit7CisJaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRy -KGRldmF0dHIpLT5pbmRleDsKKwlpbnQgc3RhdHVzOworCisJc3RhdHVzID0gaThrX2dldF9mYW5f -c3RhdHVzKGluZGV4KTsKKwlpZiAoc3RhdHVzIDwgMCkKKwkJcmV0dXJuIC1FSU87CisJcmV0dXJu -IHNwcmludGYoYnVmLCAiJWRcbiIsIGNsYW1wX3ZhbChzdGF0dXMgKiBpOGtfcHdtX211bHQsIDAs -IDI1NSkpOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2V0X3B3bShzdHJ1Y3QgZGV2 -aWNlICpkZXYsCisJCQkJIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLAorCQkJCSBjb25z -dCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKK3sKKwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2 -X2F0dHIoYXR0ciktPmluZGV4OworCXVuc2lnbmVkIGxvbmcgdmFsOworCWludCBlcnI7CisKKwll -cnIgPSBrc3RydG91bChidWYsIDEwLCAmdmFsKTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOwor -CXZhbCA9IGNsYW1wX3ZhbChESVZfUk9VTkRfQ0xPU0VTVCh2YWwsIGk4a19wd21fbXVsdCksIDAs -IGk4a19mYW5fbWF4KTsKKworCW11dGV4X2xvY2soJmk4a19tdXRleCk7CisJZXJyID0gaThrX3Nl -dF9mYW4oaW5kZXgsIHZhbCk7CisJbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOworCisJcmV0dXJu -IGVyciA8IDAgPyAtRUlPIDogY291bnQ7Cit9CisKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIo -dGVtcDFfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDApOworc3Rh -dGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3No -b3dfdGVtcF9sYWJlbCwgTlVMTCwKKwkJCSAgMCk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS -KHRlbXAyX2lucHV0LCBTX0lSVUdPLCBpOGtfaHdtb25fc2hvd190ZW1wLCBOVUxMLCAxKTsKK3N0 -YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9z -aG93X3RlbXBfbGFiZWwsIE5VTEwsCisJCQkgIDEpOworc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRU -Uih0ZW1wM19pbnB1dCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcCwgTlVMTCwgMik7Citz -dGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX2xhYmVsLCBTX0lSVUdPLCBpOGtfaHdtb25f -c2hvd190ZW1wX2xhYmVsLCBOVUxMLAorCQkJICAyKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FU -VFIodGVtcDRfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDMpOwor -c3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wNF9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9u -X3Nob3dfdGVtcF9sYWJlbCwgTlVMTCwKKwkJCSAgMyk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9B -VFRSKGZhbjFfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X2ZhbiwgTlVMTCwgMCk7Citz -dGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKGZhbjFfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9z -aG93X2Zhbl9sYWJlbCwgTlVMTCwKKwkJCSAgMCk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS -KHB3bTEsIFNfSVJVR08gfCBTX0lXVVNSLCBpOGtfaHdtb25fc2hvd19wd20sCisJCQkgIGk4a19o -d21vbl9zZXRfcHdtLCAwKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFuMl9pbnB1dCwg -U19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuLCBOVUxMLAorCQkJICAxKTsKK3N0YXRpYyBTRU5T -T1JfREVWSUNFX0FUVFIoZmFuMl9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuX2xh -YmVsLCBOVUxMLAorCQkJICAxKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIocHdtMiwgU19J -UlVHTyB8IFNfSVdVU1IsIGk4a19od21vbl9zaG93X3B3bSwKKwkJCSAgaThrX2h3bW9uX3NldF9w -d20sIDEpOworCitzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZSAqaThrX2F0dHJzW10gPSB7CisJJnNl -bnNvcl9kZXZfYXR0cl90ZW1wMV9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAwICovCisJJnNlbnNv -cl9kZXZfYXR0cl90ZW1wMV9sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAxICovCisJJnNlbnNvcl9k -ZXZfYXR0cl90ZW1wMl9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAyICovCisJJnNlbnNvcl9kZXZf -YXR0cl90ZW1wMl9sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAzICovCisJJnNlbnNvcl9kZXZfYXR0 -cl90ZW1wM19pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiA0ICovCisJJnNlbnNvcl9kZXZfYXR0cl90 -ZW1wM19sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiA1ICovCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1w -NF9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiA2ICovCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9s -YWJlbC5kZXZfYXR0ci5hdHRyLAkvKiA3ICovCisJJnNlbnNvcl9kZXZfYXR0cl9mYW4xX2lucHV0 -LmRldl9hdHRyLmF0dHIsCS8qIDggKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjFfbGFiZWwuZGV2 -X2F0dHIuYXR0ciwJLyogOSAqLworCSZzZW5zb3JfZGV2X2F0dHJfcHdtMS5kZXZfYXR0ci5hdHRy -LAkJLyogMTAgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjJfaW5wdXQuZGV2X2F0dHIuYXR0ciwJ -LyogMTEgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjJfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyog -MTIgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX3B3bTIuZGV2X2F0dHIuYXR0ciwJCS8qIDEzICovCisJ -TlVMTAorfTsKKworc3RhdGljIHVtb2RlX3QgaThrX2lzX3Zpc2libGUoc3RydWN0IGtvYmplY3Qg -KmtvYmosIHN0cnVjdCBhdHRyaWJ1dGUgKmF0dHIsCisJCQkgICAgICBpbnQgaW5kZXgpCit7CisJ -aWYgKGluZGV4ID49IDAgJiYgaW5kZXggPD0gMSAmJgorCSAgICAhKGk4a19od21vbl9mbGFncyAm -IEk4S19IV01PTl9IQVZFX1RFTVAxKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDIgJiYg -aW5kZXggPD0gMyAmJgorCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RF -TVAyKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDQgJiYgaW5kZXggPD0gNSAmJgorCSAg -ICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RFTVAzKSkKKwkJcmV0dXJuIDA7 -CisJaWYgKGluZGV4ID49IDYgJiYgaW5kZXggPD0gNyAmJgorCSAgICAhKGk4a19od21vbl9mbGFn -cyAmIEk4S19IV01PTl9IQVZFX1RFTVA0KSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDgg -JiYgaW5kZXggPD0gMTAgJiYKKwkgICAgIShpOGtfaHdtb25fZmxhZ3MgJiBJOEtfSFdNT05fSEFW -RV9GQU4xKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDExICYmIGluZGV4IDw9IDEzICYm -CisJICAgICEoaThrX2h3bW9uX2ZsYWdzICYgSThLX0hXTU9OX0hBVkVfRkFOMikpCisJCXJldHVy -biAwOworCisJcmV0dXJuIGF0dHItPm1vZGU7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgYXR0 -cmlidXRlX2dyb3VwIGk4a19ncm91cCA9IHsKKwkuYXR0cnMgPSBpOGtfYXR0cnMsCisJLmlzX3Zp -c2libGUgPSBpOGtfaXNfdmlzaWJsZSwKK307CitfX0FUVFJJQlVURV9HUk9VUFMoaThrKTsKKwor -c3RhdGljIGludCBfX2luaXQgaThrX2luaXRfaHdtb24odm9pZCkKK3sKKwlpbnQgZXJyOworCisJ -aThrX2h3bW9uX2ZsYWdzID0gMDsKKworCS8qIENQVSB0ZW1wZXJhdHVyZSBhdHRyaWJ1dGVzLCBp -ZiB0ZW1wZXJhdHVyZSB0eXBlIGlzIE9LICovCisJZXJyID0gaThrX2dldF90ZW1wX3R5cGUoMCk7 -CisJaWYgKGVyciA+PSAwKQorCQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfVEVN -UDE7CisJLyogY2hlY2sgZm9yIGFkZGl0aW9uYWwgdGVtcGVyYXR1cmUgc2Vuc29ycyAqLworCWVy -ciA9IGk4a19nZXRfdGVtcF90eXBlKDEpOworCWlmIChlcnIgPj0gMCkKKwkJaThrX2h3bW9uX2Zs -YWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVAyOworCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDIp -OworCWlmIChlcnIgPj0gMCkKKwkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RF -TVAzOworCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDMpOworCWlmIChlcnIgPj0gMCkKKwkJaThr -X2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVA0OworCisJLyogRmlyc3QgZmFuIGF0 -dHJpYnV0ZXMsIGlmIGZhbiB0eXBlIGlzIE9LICovCisJZXJyID0gaThrX2dldF9mYW5fdHlwZSgw -KTsKKwlpZiAoZXJyID49IDApCisJCWk4a19od21vbl9mbGFncyB8PSBJOEtfSFdNT05fSEFWRV9G -QU4xOworCisJLyogU2Vjb25kIGZhbiBhdHRyaWJ1dGVzLCBpZiBmYW4gdHlwZSBpcyBPSyAqLwor -CWVyciA9IGk4a19nZXRfZmFuX3R5cGUoMSk7CisJaWYgKGVyciA+PSAwKQorCQlpOGtfaHdtb25f -ZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfRkFOMjsKKworCWk4a19od21vbl9kZXYgPSBod21vbl9k -ZXZpY2VfcmVnaXN0ZXJfd2l0aF9ncm91cHMoTlVMTCwgImk4ayIsIE5VTEwsCisJCQkJCQkJICBp -OGtfZ3JvdXBzKTsKKwlpZiAoSVNfRVJSKGk4a19od21vbl9kZXYpKSB7CisJCWVyciA9IFBUUl9F -UlIoaThrX2h3bW9uX2Rldik7CisJCWk4a19od21vbl9kZXYgPSBOVUxMOworCQlwcl9lcnIoImh3 -bW9uIHJlZ2lzdHJhdGlvbiBmYWlsZWQgKCVkKVxuIiwgZXJyKTsKKwkJcmV0dXJuIGVycjsKKwl9 -CisJcmV0dXJuIDA7Cit9CisKK3N0cnVjdCBpOGtfY29uZmlnX2RhdGEgeworCXVpbnQgZmFuX211 -bHQ7CisJdWludCBmYW5fbWF4OworfTsKKworZW51bSBpOGtfY29uZmlncyB7CisJREVMTF9MQVRJ -VFVERV9ENTIwLAorCURFTExfUFJFQ0lTSU9OXzQ5MCwKKwlERUxMX1NUVURJTywKKwlERUxMX1hQ -UywKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaThrX2NvbmZpZ19kYXRhIGk4a19jb25maWdf -ZGF0YVtdID0geworCVtERUxMX0xBVElUVURFX0Q1MjBdID0geworCQkuZmFuX211bHQgPSAxLAor -CQkuZmFuX21heCA9IEk4S19GQU5fVFVSQk8sCisJfSwKKwlbREVMTF9QUkVDSVNJT05fNDkwXSA9 -IHsKKwkJLmZhbl9tdWx0ID0gMSwKKwkJLmZhbl9tYXggPSBJOEtfRkFOX1RVUkJPLAorCX0sCisJ -W0RFTExfU1RVRElPXSA9IHsKKwkJLmZhbl9tdWx0ID0gMSwKKwkJLmZhbl9tYXggPSBJOEtfRkFO -X0hJR0gsCisJfSwKKwlbREVMTF9YUFNdID0geworCQkuZmFuX211bHQgPSAxLAorCQkuZmFuX21h -eCA9IEk4S19GQU5fSElHSCwKKwl9LAorfTsKKworc3RhdGljIHN0cnVjdCBkbWlfc3lzdGVtX2lk -IGk4a19kbWlfdGFibGVbXSBfX2luaXRkYXRhID0geworCXsKKwkJLmlkZW50ID0gIkRlbGwgSW5z -cGlyb24iLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRl -bGwgQ29tcHV0ZXIiKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiSW5zcGlyb24i -KSwKKwkJfSwKKwl9LAorCXsKKwkJLmlkZW50ID0gIkRlbGwgTGF0aXR1ZGUiLAorCQkubWF0Y2hl -cyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKKwkJ -CURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKKwkJfSwKKwl9LAorCXsK -KwkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24gMiIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01B -VENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RV -Q1RfTkFNRSwgIkluc3Bpcm9uIiksCisJCX0sCisJfSwKKwl7CisJCS5pZGVudCA9ICJEZWxsIExh -dGl0dWRlIEQ1MjAiLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRP -UiwgIkRlbGwgSW5jLiIpLAorCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJMYXRpdHVk -ZSBENTIwIiksCisJCX0sCisJCS5kcml2ZXJfZGF0YSA9ICh2b2lkICopJmk4a19jb25maWdfZGF0 -YVtERUxMX0xBVElUVURFX0Q1MjBdLAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVsbCBMYXRpdHVk -ZSAyIiwKKwkJLm1hdGNoZXMgPSB7CisJCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxs -IEluYy4iKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKKwkJ -fSwKKwl9LAorCXsJLyogVUsgSW5zcGlyb24gNjQwMCAgKi8KKwkJLmlkZW50ID0gIkRlbGwgSW5z -cGlyb24gMyIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAi -RGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1NMDYxIiksCisJ -CX0sCisJfSwKKwl7CisJCS5pZGVudCA9ICJEZWxsIEluc3Bpcm9uIDMiLAorCQkubWF0Y2hlcyA9 -IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAorCQkJRE1JX01B -VENIKERNSV9QUk9EVUNUX05BTUUsICJNUDA2MSIpLAorCQl9LAorCX0sCisJeworCQkuaWRlbnQg -PSAiRGVsbCBQcmVjaXNpb24gNDkwIiwKKwkJLm1hdGNoZXMgPSB7CisJCQlETUlfTUFUQ0goRE1J -X1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1F -LAorCQkJCSAgIlByZWNpc2lvbiBXb3JrU3RhdGlvbiA0OTAiKSwKKwkJfSwKKwkJLmRyaXZlcl9k -YXRhID0gKHZvaWQgKikmaThrX2NvbmZpZ19kYXRhW0RFTExfUFJFQ0lTSU9OXzQ5MF0sCisJfSwK -Kwl7CisJCS5pZGVudCA9ICJEZWxsIFByZWNpc2lvbiIsCisJCS5tYXRjaGVzID0geworCQkJRE1J -X01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BS -T0RVQ1RfTkFNRSwgIlByZWNpc2lvbiIpLAorCQl9LAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVs -bCBWb3N0cm8iLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwg -IkRlbGwgSW5jLiIpLAorCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJWb3N0cm8iKSwK -KwkJfSwKKwl9LAorCXsKKwkJLmlkZW50ID0gIkRlbGwgWFBTNDIxIiwKKwkJLm1hdGNoZXMgPSB7 -CisJCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKKwkJCURNSV9NQVRD -SChETUlfUFJPRFVDVF9OQU1FLCAiWFBTIEw0MjFYIiksCisJCX0sCisJfSwKKwl7CisJCS5pZGVu -dCA9ICJEZWxsIFN0dWRpbyIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9TWVNf -VkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlN0 -dWRpbyIpLAorCQl9LAorCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFb -REVMTF9TVFVESU9dLAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVsbCBYUFMgMTMiLAorCQkubWF0 -Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAorCQkJ -RE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJYUFMxMyIpLAorCQl9LAorCQkuZHJpdmVyX2Rh -dGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9YUFNdLAorCX0sCisJeworCQkuaWRl -bnQgPSAiRGVsbCBYUFMgTTE0MCIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9T -WVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwg -Ik1YQzA1MSIpLAorCQl9LAorCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2Rh -dGFbREVMTF9YUFNdLAorCX0sCisJeyB9Cit9OworCitNT0RVTEVfREVWSUNFX1RBQkxFKGRtaSwg -aThrX2RtaV90YWJsZSk7CisKKy8qCisgKiBQcm9iZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgc3Vw -cG9ydGVkIGxhcHRvcC4KKyAqLworc3RhdGljIGludCBfX2luaXQgaThrX3Byb2JlKHZvaWQpCit7 -CisJY29uc3Qgc3RydWN0IGRtaV9zeXN0ZW1faWQgKmlkOworCWludCBmYW4sIHJldDsKKworCS8q -CisJICogR2V0IERNSSBpbmZvcm1hdGlvbgorCSAqLworCWlmICghZG1pX2NoZWNrX3N5c3RlbShp -OGtfZG1pX3RhYmxlKSkgeworCQlpZiAoIWlnbm9yZV9kbWkgJiYgIWZvcmNlKQorCQkJcmV0dXJu -IC1FTk9ERVY7CisKKwkJcHJfaW5mbygibm90IHJ1bm5pbmcgb24gYSBzdXBwb3J0ZWQgRGVsbCBz -eXN0ZW0uXG4iKTsKKwkJcHJfaW5mbygidmVuZG9yPSVzLCBtb2RlbD0lcywgdmVyc2lvbj0lc1xu -IiwKKwkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX1NZU19WRU5ET1IpLAorCQkJaThrX2dldF9kbWlf -ZGF0YShETUlfUFJPRFVDVF9OQU1FKSwKKwkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX0JJT1NfVkVS -U0lPTikpOworCX0KKworCXN0cmxjcHkoYmlvc192ZXJzaW9uLCBpOGtfZ2V0X2RtaV9kYXRhKERN -SV9CSU9TX1ZFUlNJT04pLAorCQlzaXplb2YoYmlvc192ZXJzaW9uKSk7CisKKwkvKgorCSAqIEdl -dCBTTU0gRGVsbCBzaWduYXR1cmUKKwkgKi8KKwlpZiAoaThrX2dldF9kZWxsX3NpZ25hdHVyZShJ -OEtfU01NX0dFVF9ERUxMX1NJRzEpICYmCisJICAgIGk4a19nZXRfZGVsbF9zaWduYXR1cmUoSThL -X1NNTV9HRVRfREVMTF9TSUcyKSkgeworCQlwcl9lcnIoInVuYWJsZSB0byBnZXQgU01NIERlbGwg -c2lnbmF0dXJlXG4iKTsKKwkJaWYgKCFmb3JjZSkKKwkJCXJldHVybiAtRU5PREVWOworCX0KKwor -CS8qCisJICogU2V0IGZhbiBtdWx0aXBsaWVyIGFuZCBtYXhpbWFsIGZhbiBzcGVlZCBmcm9tIGRt -aSBjb25maWcKKwkgKiBWYWx1ZXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbWV0ZXJzIG92ZXJy -aWRlIHZhbHVlcyBmcm9tIGRtaQorCSAqLworCWlkID0gZG1pX2ZpcnN0X21hdGNoKGk4a19kbWlf -dGFibGUpOworCWlmIChpZCAmJiBpZC0+ZHJpdmVyX2RhdGEpIHsKKwkJY29uc3Qgc3RydWN0IGk4 -a19jb25maWdfZGF0YSAqY29uZiA9IGlkLT5kcml2ZXJfZGF0YTsKKwkJaWYgKCFmYW5fbXVsdCAm -JiBjb25mLT5mYW5fbXVsdCkKKwkJCWZhbl9tdWx0ID0gY29uZi0+ZmFuX211bHQ7CisJCWlmICgh -ZmFuX21heCAmJiBjb25mLT5mYW5fbWF4KQorCQkJZmFuX21heCA9IGNvbmYtPmZhbl9tYXg7CisJ -fQorCisJaThrX2Zhbl9tYXggPSBmYW5fbWF4ID8gOiBJOEtfRkFOX0hJR0g7CS8qIE11c3Qgbm90 -IGJlIDAgKi8KKwlpOGtfcHdtX211bHQgPSBESVZfUk9VTkRfVVAoMjU1LCBpOGtfZmFuX21heCk7 -CisKKwlpZiAoIWZhbl9tdWx0KSB7CisJCS8qCisJCSAqIEF1dG9kZXRlY3QgZmFuIG11bHRpcGxp -ZXIgYmFzZWQgb24gbm9taW5hbCBycG0KKwkJICogSWYgZmFuIHJlcG9ydHMgcnBtIHZhbHVlIHRv -byBoaWdoIHRoZW4gc2V0IG11bHRpcGxpZXIgdG8gMQorCQkgKi8KKwkJZm9yIChmYW4gPSAwOyBm -YW4gPCAyOyArK2ZhbikgeworCQkJcmV0ID0gaThrX2dldF9mYW5fbm9taW5hbF9zcGVlZChmYW4s -IGk4a19mYW5fbWF4KTsKKwkJCWlmIChyZXQgPCAwKQorCQkJCWNvbnRpbnVlOworCQkJaWYgKHJl -dCA+IEk4S19GQU5fTUFYX1JQTSkKKwkJCQlpOGtfZmFuX211bHQgPSAxOworCQkJYnJlYWs7CisJ -CX0KKwl9IGVsc2UgeworCQkvKiBGYW4gbXVsdGlwbGllciB3YXMgc3BlY2lmaWVkIGluIG1vZHVs -ZSBwYXJhbSBvciBpbiBkbWkgKi8KKwkJaThrX2Zhbl9tdWx0ID0gZmFuX211bHQ7CisJfQorCisJ -cmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgX19pbml0IGk4a19pbml0KHZvaWQpCit7CisJc3Ry -dWN0IHByb2NfZGlyX2VudHJ5ICpwcm9jX2k4azsKKwlpbnQgZXJyOworCisJLyogQXJlIHdlIHJ1 -bm5pbmcgb24gYW4gc3VwcG9ydGVkIGxhcHRvcD8gKi8KKwlpZiAoaThrX3Byb2JlKCkpCisJCXJl -dHVybiAtRU5PREVWOworCisJLyogUmVnaXN0ZXIgdGhlIHByb2MgZW50cnkgKi8KKwlwcm9jX2k4 -ayA9IHByb2NfY3JlYXRlKCJpOGsiLCAwLCBOVUxMLCAmaThrX2ZvcHMpOworCWlmICghcHJvY19p -OGspCisJCXJldHVybiAtRU5PRU5UOworCisJZXJyID0gaThrX2luaXRfaHdtb24oKTsKKwlpZiAo -ZXJyKQorCQlnb3RvIGV4aXRfcmVtb3ZlX3Byb2M7CisKKwlyZXR1cm4gMDsKKworIGV4aXRfcmVt -b3ZlX3Byb2M6CisJcmVtb3ZlX3Byb2NfZW50cnkoImk4ayIsIE5VTEwpOworCXJldHVybiBlcnI7 -Cit9CisKK3N0YXRpYyB2b2lkIF9fZXhpdCBpOGtfZXhpdCh2b2lkKQoreworCWh3bW9uX2Rldmlj -ZV91bnJlZ2lzdGVyKGk4a19od21vbl9kZXYpOworCXJlbW92ZV9wcm9jX2VudHJ5KCJpOGsiLCBO -VUxMKTsKK30KKworbW9kdWxlX2luaXQoaThrX2luaXQpOworbW9kdWxlX2V4aXQoaThrX2V4aXQp -OwotLSAKMS43LjkuNQoKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f -X19fX19fCmxtLXNlbnNvcnMgbWFpbGluZyBsaXN0CmxtLXNlbnNvcnNAbG0tc2Vuc29ycy5vcmcK -aHR0cDovL2xpc3RzLmxtLXNlbnNvcnMub3JnL21haWxtYW4vbGlzdGluZm8vbG0tc2Vuc29ycw= +This commit moves i8k driver to hwmon tree under name dell-smm-hwmon which is +better name then abbreviation i8k. For backward compatibility is added macro +MODULE_ALIAS("i8k") so modprobe will load driver also old name i8k. CONFIG_I8K +compile option was not changed. + +This commit also adds me as maintainer of this new dell-smm-hwmon driver and +remove Guenter Roeck from list who is implicit maintainer all hwmon drivers. + +Signed-off-by: Pali Rohár <pali.rohar@gmail.com> +--- + MAINTAINERS | 4 +- + drivers/char/Makefile | 1 - + drivers/char/i8k.c | 1005 --------------------------------------- + drivers/hwmon/Makefile | 1 + + drivers/hwmon/dell-smm-hwmon.c | 1007 ++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 1010 insertions(+), 1008 deletions(-) + delete mode 100644 drivers/char/i8k.c + create mode 100644 drivers/hwmon/dell-smm-hwmon.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 88c09ca..e54a07e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3063,9 +3063,9 @@ S: Maintained + F: drivers/platform/x86/dell-laptop.c + + DELL LAPTOP SMM DRIVER +-M: Guenter Roeck <linux@roeck-us.net> ++M: Pali Rohár <pali.rohar@gmail.com> + S: Maintained +-F: drivers/char/i8k.c ++F: drivers/hwmon/dell-smm-hwmon.c + F: include/uapi/linux/i8k.h + + DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas) +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index d06cde26..1d9cf00 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -36,7 +36,6 @@ else + obj-$(CONFIG_NVRAM) += nvram.o + endif + obj-$(CONFIG_TOSHIBA) += toshiba.o +-obj-$(CONFIG_I8K) += i8k.o + obj-$(CONFIG_DS1620) += ds1620.o + obj-$(CONFIG_HW_RANDOM) += hw_random/ + obj-$(CONFIG_PPDEV) += ppdev.o +diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c +deleted file mode 100644 +index 24cc4ed..0000000 +--- a/drivers/char/i8k.c ++++ /dev/null +@@ -1,1005 +0,0 @@ +-/* +- * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops. +- * +- * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> +- * +- * Hwmon integration: +- * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> +- * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net> +- * Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com> +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2, or (at your option) any +- * later version. +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- */ +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include <linux/delay.h> +-#include <linux/module.h> +-#include <linux/types.h> +-#include <linux/init.h> +-#include <linux/proc_fs.h> +-#include <linux/seq_file.h> +-#include <linux/dmi.h> +-#include <linux/capability.h> +-#include <linux/mutex.h> +-#include <linux/hwmon.h> +-#include <linux/hwmon-sysfs.h> +-#include <linux/uaccess.h> +-#include <linux/io.h> +-#include <linux/sched.h> +- +-#include <linux/i8k.h> +- +-#define I8K_SMM_FN_STATUS 0x0025 +-#define I8K_SMM_POWER_STATUS 0x0069 +-#define I8K_SMM_SET_FAN 0x01a3 +-#define I8K_SMM_GET_FAN 0x00a3 +-#define I8K_SMM_GET_SPEED 0x02a3 +-#define I8K_SMM_GET_FAN_TYPE 0x03a3 +-#define I8K_SMM_GET_NOM_SPEED 0x04a3 +-#define I8K_SMM_GET_TEMP 0x10a3 +-#define I8K_SMM_GET_TEMP_TYPE 0x11a3 +-#define I8K_SMM_GET_DELL_SIG1 0xfea3 +-#define I8K_SMM_GET_DELL_SIG2 0xffa3 +- +-#define I8K_FAN_MULT 30 +-#define I8K_FAN_MAX_RPM 30000 +-#define I8K_MAX_TEMP 127 +- +-#define I8K_FN_NONE 0x00 +-#define I8K_FN_UP 0x01 +-#define I8K_FN_DOWN 0x02 +-#define I8K_FN_MUTE 0x04 +-#define I8K_FN_MASK 0x07 +-#define I8K_FN_SHIFT 8 +- +-#define I8K_POWER_AC 0x05 +-#define I8K_POWER_BATTERY 0x01 +- +-static DEFINE_MUTEX(i8k_mutex); +-static char bios_version[4]; +-static struct device *i8k_hwmon_dev; +-static u32 i8k_hwmon_flags; +-static uint i8k_fan_mult = I8K_FAN_MULT; +-static uint i8k_pwm_mult; +-static uint i8k_fan_max = I8K_FAN_HIGH; +- +-#define I8K_HWMON_HAVE_TEMP1 (1 << 0) +-#define I8K_HWMON_HAVE_TEMP2 (1 << 1) +-#define I8K_HWMON_HAVE_TEMP3 (1 << 2) +-#define I8K_HWMON_HAVE_TEMP4 (1 << 3) +-#define I8K_HWMON_HAVE_FAN1 (1 << 4) +-#define I8K_HWMON_HAVE_FAN2 (1 << 5) +- +-MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); +-MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); +-MODULE_LICENSE("GPL"); +- +-static bool force; +-module_param(force, bool, 0); +-MODULE_PARM_DESC(force, "Force loading without checking for supported models"); +- +-static bool ignore_dmi; +-module_param(ignore_dmi, bool, 0); +-MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); +- +-static bool restricted; +-module_param(restricted, bool, 0); +-MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); +- +-static bool power_status; +-module_param(power_status, bool, 0600); +-MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); +- +-static uint fan_mult; +-module_param(fan_mult, uint, 0); +-MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)"); +- +-static uint fan_max; +-module_param(fan_max, uint, 0); +-MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)"); +- +-static int i8k_open_fs(struct inode *inode, struct file *file); +-static long i8k_ioctl(struct file *, unsigned int, unsigned long); +- +-static const struct file_operations i8k_fops = { +- .owner = THIS_MODULE, +- .open = i8k_open_fs, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +- .unlocked_ioctl = i8k_ioctl, +-}; +- +-struct smm_regs { +- unsigned int eax; +- unsigned int ebx __packed; +- unsigned int ecx __packed; +- unsigned int edx __packed; +- unsigned int esi __packed; +- unsigned int edi __packed; +-}; +- +-static inline const char *i8k_get_dmi_data(int field) +-{ +- const char *dmi_data = dmi_get_system_info(field); +- +- return dmi_data && *dmi_data ? dmi_data : "?"; +-} +- +-/* +- * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. +- */ +-static int i8k_smm(struct smm_regs *regs) +-{ +- int rc; +- int eax = regs->eax; +- cpumask_var_t old_mask; +- +- /* SMM requires CPU 0 */ +- if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) +- return -ENOMEM; +- cpumask_copy(old_mask, ¤t->cpus_allowed); +- rc = set_cpus_allowed_ptr(current, cpumask_of(0)); +- if (rc) +- goto out; +- if (smp_processor_id() != 0) { +- rc = -EBUSY; +- goto out; +- } +- +-#if defined(CONFIG_X86_64) +- asm volatile("pushq %%rax\n\t" +- "movl 0(%%rax),%%edx\n\t" +- "pushq %%rdx\n\t" +- "movl 4(%%rax),%%ebx\n\t" +- "movl 8(%%rax),%%ecx\n\t" +- "movl 12(%%rax),%%edx\n\t" +- "movl 16(%%rax),%%esi\n\t" +- "movl 20(%%rax),%%edi\n\t" +- "popq %%rax\n\t" +- "out %%al,$0xb2\n\t" +- "out %%al,$0x84\n\t" +- "xchgq %%rax,(%%rsp)\n\t" +- "movl %%ebx,4(%%rax)\n\t" +- "movl %%ecx,8(%%rax)\n\t" +- "movl %%edx,12(%%rax)\n\t" +- "movl %%esi,16(%%rax)\n\t" +- "movl %%edi,20(%%rax)\n\t" +- "popq %%rdx\n\t" +- "movl %%edx,0(%%rax)\n\t" +- "pushfq\n\t" +- "popq %%rax\n\t" +- "andl $1,%%eax\n" +- : "=a"(rc) +- : "a"(regs) +- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); +-#else +- asm volatile("pushl %%eax\n\t" +- "movl 0(%%eax),%%edx\n\t" +- "push %%edx\n\t" +- "movl 4(%%eax),%%ebx\n\t" +- "movl 8(%%eax),%%ecx\n\t" +- "movl 12(%%eax),%%edx\n\t" +- "movl 16(%%eax),%%esi\n\t" +- "movl 20(%%eax),%%edi\n\t" +- "popl %%eax\n\t" +- "out %%al,$0xb2\n\t" +- "out %%al,$0x84\n\t" +- "xchgl %%eax,(%%esp)\n\t" +- "movl %%ebx,4(%%eax)\n\t" +- "movl %%ecx,8(%%eax)\n\t" +- "movl %%edx,12(%%eax)\n\t" +- "movl %%esi,16(%%eax)\n\t" +- "movl %%edi,20(%%eax)\n\t" +- "popl %%edx\n\t" +- "movl %%edx,0(%%eax)\n\t" +- "lahf\n\t" +- "shrl $8,%%eax\n\t" +- "andl $1,%%eax\n" +- : "=a"(rc) +- : "a"(regs) +- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); +-#endif +- if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) +- rc = -EINVAL; +- +-out: +- set_cpus_allowed_ptr(current, old_mask); +- free_cpumask_var(old_mask); +- return rc; +-} +- +-/* +- * Read the Fn key status. +- */ +-static int i8k_get_fn_status(void) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; +- int rc; +- +- rc = i8k_smm(®s); +- if (rc < 0) +- return rc; +- +- switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { +- case I8K_FN_UP: +- return I8K_VOL_UP; +- case I8K_FN_DOWN: +- return I8K_VOL_DOWN; +- case I8K_FN_MUTE: +- return I8K_VOL_MUTE; +- default: +- return 0; +- } +-} +- +-/* +- * Read the power status. +- */ +-static int i8k_get_power_status(void) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; +- int rc; +- +- rc = i8k_smm(®s); +- if (rc < 0) +- return rc; +- +- return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; +-} +- +-/* +- * Read the fan status. +- */ +-static int i8k_get_fan_status(int fan) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; +- +- regs.ebx = fan & 0xff; +- return i8k_smm(®s) ? : regs.eax & 0xff; +-} +- +-/* +- * Read the fan speed in RPM. +- */ +-static int i8k_get_fan_speed(int fan) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; +- +- regs.ebx = fan & 0xff; +- return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; +-} +- +-/* +- * Read the fan type. +- */ +-static int i8k_get_fan_type(int fan) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; +- +- regs.ebx = fan & 0xff; +- return i8k_smm(®s) ? : regs.eax & 0xff; +-} +- +-/* +- * Read the fan nominal rpm for specific fan speed. +- */ +-static int i8k_get_fan_nominal_speed(int fan, int speed) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; +- +- regs.ebx = (fan & 0xff) | (speed << 8); +- return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; +-} +- +-/* +- * Set the fan speed (off, low, high). Returns the new fan status. +- */ +-static int i8k_set_fan(int fan, int speed) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; +- +- speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); +- regs.ebx = (fan & 0xff) | (speed << 8); +- +- return i8k_smm(®s) ? : i8k_get_fan_status(fan); +-} +- +-static int i8k_get_temp_type(int sensor) +-{ +- struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, }; +- +- regs.ebx = sensor & 0xff; +- return i8k_smm(®s) ? : regs.eax & 0xff; +-} +- +-/* +- * Read the cpu temperature. +- */ +-static int _i8k_get_temp(int sensor) +-{ +- struct smm_regs regs = { +- .eax = I8K_SMM_GET_TEMP, +- .ebx = sensor & 0xff, +- }; +- +- return i8k_smm(®s) ? : regs.eax & 0xff; +-} +- +-static int i8k_get_temp(int sensor) +-{ +- int temp = _i8k_get_temp(sensor); +- +- /* +- * Sometimes the temperature sensor returns 0x99, which is out of range. +- * In this case we retry (once) before returning an error. +- # 1003655137 00000058 00005a4b +- # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees +- # 1003655139 00000054 00005c52 +- */ +- if (temp == 0x99) { +- msleep(100); +- temp = _i8k_get_temp(sensor); +- } +- /* +- * Return -ENODATA for all invalid temperatures. +- * +- * Known instances are the 0x99 value as seen above as well as +- * 0xc1 (193), which may be returned when trying to read the GPU +- * temperature if the system supports a GPU and it is currently +- * turned off. +- */ +- if (temp > I8K_MAX_TEMP) +- return -ENODATA; +- +- return temp; +-} +- +-static int i8k_get_dell_signature(int req_fn) +-{ +- struct smm_regs regs = { .eax = req_fn, }; +- int rc; +- +- rc = i8k_smm(®s); +- if (rc < 0) +- return rc; +- +- return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; +-} +- +-static int +-i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg) +-{ +- int val = 0; +- int speed; +- unsigned char buff[16]; +- int __user *argp = (int __user *)arg; +- +- if (!argp) +- return -EINVAL; +- +- switch (cmd) { +- case I8K_BIOS_VERSION: +- val = (bios_version[0] << 16) | +- (bios_version[1] << 8) | bios_version[2]; +- break; +- +- case I8K_MACHINE_ID: +- memset(buff, 0, 16); +- strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), +- sizeof(buff)); +- break; +- +- case I8K_FN_STATUS: +- val = i8k_get_fn_status(); +- break; +- +- case I8K_POWER_STATUS: +- val = i8k_get_power_status(); +- break; +- +- case I8K_GET_TEMP: +- val = i8k_get_temp(0); +- break; +- +- case I8K_GET_SPEED: +- if (copy_from_user(&val, argp, sizeof(int))) +- return -EFAULT; +- +- val = i8k_get_fan_speed(val); +- break; +- +- case I8K_GET_FAN: +- if (copy_from_user(&val, argp, sizeof(int))) +- return -EFAULT; +- +- val = i8k_get_fan_status(val); +- break; +- +- case I8K_SET_FAN: +- if (restricted && !capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- if (copy_from_user(&val, argp, sizeof(int))) +- return -EFAULT; +- +- if (copy_from_user(&speed, argp + 1, sizeof(int))) +- return -EFAULT; +- +- val = i8k_set_fan(val, speed); +- break; +- +- default: +- return -EINVAL; +- } +- +- if (val < 0) +- return val; +- +- switch (cmd) { +- case I8K_BIOS_VERSION: +- if (copy_to_user(argp, &val, 4)) +- return -EFAULT; +- +- break; +- case I8K_MACHINE_ID: +- if (copy_to_user(argp, buff, 16)) +- return -EFAULT; +- +- break; +- default: +- if (copy_to_user(argp, &val, sizeof(int))) +- return -EFAULT; +- +- break; +- } +- +- return 0; +-} +- +-static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +-{ +- long ret; +- +- mutex_lock(&i8k_mutex); +- ret = i8k_ioctl_unlocked(fp, cmd, arg); +- mutex_unlock(&i8k_mutex); +- +- return ret; +-} +- +-/* +- * Print the information for /proc/i8k. +- */ +-static int i8k_proc_show(struct seq_file *seq, void *offset) +-{ +- int fn_key, cpu_temp, ac_power; +- int left_fan, right_fan, left_speed, right_speed; +- +- cpu_temp = i8k_get_temp(0); /* 11100 µs */ +- left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ +- right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ +- left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ +- right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ +- fn_key = i8k_get_fn_status(); /* 750 µs */ +- if (power_status) +- ac_power = i8k_get_power_status(); /* 14700 µs */ +- else +- ac_power = -1; +- +- /* +- * Info: +- * +- * 1) Format version (this will change if format changes) +- * 2) BIOS version +- * 3) BIOS machine ID +- * 4) Cpu temperature +- * 5) Left fan status +- * 6) Right fan status +- * 7) Left fan speed +- * 8) Right fan speed +- * 9) AC power +- * 10) Fn Key status +- */ +- return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", +- I8K_PROC_FMT, +- bios_version, +- i8k_get_dmi_data(DMI_PRODUCT_SERIAL), +- cpu_temp, +- left_fan, right_fan, left_speed, right_speed, +- ac_power, fn_key); +-} +- +-static int i8k_open_fs(struct inode *inode, struct file *file) +-{ +- return single_open(file, i8k_proc_show, NULL); +-} +- +- +-/* +- * Hwmon interface +- */ +- +-static ssize_t i8k_hwmon_show_temp_label(struct device *dev, +- struct device_attribute *devattr, +- char *buf) +-{ +- static const char * const labels[] = { +- "CPU", +- "GPU", +- "SODIMM", +- "Other", +- "Ambient", +- "Other", +- }; +- int index = to_sensor_dev_attr(devattr)->index; +- int type; +- +- type = i8k_get_temp_type(index); +- if (type < 0) +- return type; +- if (type >= ARRAY_SIZE(labels)) +- type = ARRAY_SIZE(labels) - 1; +- return sprintf(buf, "%s\n", labels[type]); +-} +- +-static ssize_t i8k_hwmon_show_temp(struct device *dev, +- struct device_attribute *devattr, +- char *buf) +-{ +- int index = to_sensor_dev_attr(devattr)->index; +- int temp; +- +- temp = i8k_get_temp(index); +- if (temp < 0) +- return temp; +- return sprintf(buf, "%d\n", temp * 1000); +-} +- +-static ssize_t i8k_hwmon_show_fan_label(struct device *dev, +- struct device_attribute *devattr, +- char *buf) +-{ +- static const char * const labels[] = { +- "Processor Fan", +- "Motherboard Fan", +- "Video Fan", +- "Power Supply Fan", +- "Chipset Fan", +- "Other Fan", +- }; +- int index = to_sensor_dev_attr(devattr)->index; +- bool dock = false; +- int type; +- +- type = i8k_get_fan_type(index); +- if (type < 0) +- return type; +- +- if (type & 0x10) { +- dock = true; +- type &= 0x0F; +- } +- +- if (type >= ARRAY_SIZE(labels)) +- type = (ARRAY_SIZE(labels) - 1); +- +- return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]); +-} +- +-static ssize_t i8k_hwmon_show_fan(struct device *dev, +- struct device_attribute *devattr, +- char *buf) +-{ +- int index = to_sensor_dev_attr(devattr)->index; +- int fan_speed; +- +- fan_speed = i8k_get_fan_speed(index); +- if (fan_speed < 0) +- return fan_speed; +- return sprintf(buf, "%d\n", fan_speed); +-} +- +-static ssize_t i8k_hwmon_show_pwm(struct device *dev, +- struct device_attribute *devattr, +- char *buf) +-{ +- int index = to_sensor_dev_attr(devattr)->index; +- int status; +- +- status = i8k_get_fan_status(index); +- if (status < 0) +- return -EIO; +- return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); +-} +- +-static ssize_t i8k_hwmon_set_pwm(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- int index = to_sensor_dev_attr(attr)->index; +- unsigned long val; +- int err; +- +- err = kstrtoul(buf, 10, &val); +- if (err) +- return err; +- val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max); +- +- mutex_lock(&i8k_mutex); +- err = i8k_set_fan(index, val); +- mutex_unlock(&i8k_mutex); +- +- return err < 0 ? -EIO : count; +-} +- +-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); +-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, +- 0); +-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); +-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, +- 1); +-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); +-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, +- 2); +-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); +-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, +- 3); +-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0); +-static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, +- 0); +-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, +- i8k_hwmon_set_pwm, 0); +-static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, +- 1); +-static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, +- 1); +-static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, +- i8k_hwmon_set_pwm, 1); +- +-static struct attribute *i8k_attrs[] = { +- &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ +- &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ +- &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ +- &sensor_dev_attr_temp2_label.dev_attr.attr, /* 3 */ +- &sensor_dev_attr_temp3_input.dev_attr.attr, /* 4 */ +- &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */ +- &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ +- &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ +- &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ +- &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ +- &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ +- &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ +- &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ +- &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ +- NULL +-}; +- +-static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, +- int index) +-{ +- if (index >= 0 && index <= 1 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) +- return 0; +- if (index >= 2 && index <= 3 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) +- return 0; +- if (index >= 4 && index <= 5 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) +- return 0; +- if (index >= 6 && index <= 7 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) +- return 0; +- if (index >= 8 && index <= 10 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) +- return 0; +- if (index >= 11 && index <= 13 && +- !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) +- return 0; +- +- return attr->mode; +-} +- +-static const struct attribute_group i8k_group = { +- .attrs = i8k_attrs, +- .is_visible = i8k_is_visible, +-}; +-__ATTRIBUTE_GROUPS(i8k); +- +-static int __init i8k_init_hwmon(void) +-{ +- int err; +- +- i8k_hwmon_flags = 0; +- +- /* CPU temperature attributes, if temperature type is OK */ +- err = i8k_get_temp_type(0); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1; +- /* check for additional temperature sensors */ +- err = i8k_get_temp_type(1); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; +- err = i8k_get_temp_type(2); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; +- err = i8k_get_temp_type(3); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; +- +- /* First fan attributes, if fan type is OK */ +- err = i8k_get_fan_type(0); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; +- +- /* Second fan attributes, if fan type is OK */ +- err = i8k_get_fan_type(1); +- if (err >= 0) +- i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; +- +- i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "i8k", NULL, +- i8k_groups); +- if (IS_ERR(i8k_hwmon_dev)) { +- err = PTR_ERR(i8k_hwmon_dev); +- i8k_hwmon_dev = NULL; +- pr_err("hwmon registration failed (%d)\n", err); +- return err; +- } +- return 0; +-} +- +-struct i8k_config_data { +- uint fan_mult; +- uint fan_max; +-}; +- +-enum i8k_configs { +- DELL_LATITUDE_D520, +- DELL_PRECISION_490, +- DELL_STUDIO, +- DELL_XPS, +-}; +- +-static const struct i8k_config_data i8k_config_data[] = { +- [DELL_LATITUDE_D520] = { +- .fan_mult = 1, +- .fan_max = I8K_FAN_TURBO, +- }, +- [DELL_PRECISION_490] = { +- .fan_mult = 1, +- .fan_max = I8K_FAN_TURBO, +- }, +- [DELL_STUDIO] = { +- .fan_mult = 1, +- .fan_max = I8K_FAN_HIGH, +- }, +- [DELL_XPS] = { +- .fan_mult = 1, +- .fan_max = I8K_FAN_HIGH, +- }, +-}; +- +-static struct dmi_system_id i8k_dmi_table[] __initdata = { +- { +- .ident = "Dell Inspiron", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), +- }, +- }, +- { +- .ident = "Dell Latitude", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), +- }, +- }, +- { +- .ident = "Dell Inspiron 2", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), +- }, +- }, +- { +- .ident = "Dell Latitude D520", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"), +- }, +- .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], +- }, +- { +- .ident = "Dell Latitude 2", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), +- }, +- }, +- { /* UK Inspiron 6400 */ +- .ident = "Dell Inspiron 3", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "MM061"), +- }, +- }, +- { +- .ident = "Dell Inspiron 3", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "MP061"), +- }, +- }, +- { +- .ident = "Dell Precision 490", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, +- "Precision WorkStation 490"), +- }, +- .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490], +- }, +- { +- .ident = "Dell Precision", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Precision"), +- }, +- }, +- { +- .ident = "Dell Vostro", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"), +- }, +- }, +- { +- .ident = "Dell XPS421", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), +- }, +- }, +- { +- .ident = "Dell Studio", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), +- }, +- .driver_data = (void *)&i8k_config_data[DELL_STUDIO], +- }, +- { +- .ident = "Dell XPS 13", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"), +- }, +- .driver_data = (void *)&i8k_config_data[DELL_XPS], +- }, +- { +- .ident = "Dell XPS M140", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), +- }, +- .driver_data = (void *)&i8k_config_data[DELL_XPS], +- }, +- { } +-}; +- +-MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); +- +-/* +- * Probe for the presence of a supported laptop. +- */ +-static int __init i8k_probe(void) +-{ +- const struct dmi_system_id *id; +- int fan, ret; +- +- /* +- * Get DMI information +- */ +- if (!dmi_check_system(i8k_dmi_table)) { +- if (!ignore_dmi && !force) +- return -ENODEV; +- +- pr_info("not running on a supported Dell system.\n"); +- pr_info("vendor=%s, model=%s, version=%s\n", +- i8k_get_dmi_data(DMI_SYS_VENDOR), +- i8k_get_dmi_data(DMI_PRODUCT_NAME), +- i8k_get_dmi_data(DMI_BIOS_VERSION)); +- } +- +- strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), +- sizeof(bios_version)); +- +- /* +- * Get SMM Dell signature +- */ +- if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && +- i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { +- pr_err("unable to get SMM Dell signature\n"); +- if (!force) +- return -ENODEV; +- } +- +- /* +- * Set fan multiplier and maximal fan speed from dmi config +- * Values specified in module parameters override values from dmi +- */ +- id = dmi_first_match(i8k_dmi_table); +- if (id && id->driver_data) { +- const struct i8k_config_data *conf = id->driver_data; +- if (!fan_mult && conf->fan_mult) +- fan_mult = conf->fan_mult; +- if (!fan_max && conf->fan_max) +- fan_max = conf->fan_max; +- } +- +- i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ +- i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); +- +- if (!fan_mult) { +- /* +- * Autodetect fan multiplier based on nominal rpm +- * If fan reports rpm value too high then set multiplier to 1 +- */ +- for (fan = 0; fan < 2; ++fan) { +- ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max); +- if (ret < 0) +- continue; +- if (ret > I8K_FAN_MAX_RPM) +- i8k_fan_mult = 1; +- break; +- } +- } else { +- /* Fan multiplier was specified in module param or in dmi */ +- i8k_fan_mult = fan_mult; +- } +- +- return 0; +-} +- +-static int __init i8k_init(void) +-{ +- struct proc_dir_entry *proc_i8k; +- int err; +- +- /* Are we running on an supported laptop? */ +- if (i8k_probe()) +- return -ENODEV; +- +- /* Register the proc entry */ +- proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); +- if (!proc_i8k) +- return -ENOENT; +- +- err = i8k_init_hwmon(); +- if (err) +- goto exit_remove_proc; +- +- return 0; +- +- exit_remove_proc: +- remove_proc_entry("i8k", NULL); +- return err; +-} +- +-static void __exit i8k_exit(void) +-{ +- hwmon_device_unregister(i8k_hwmon_dev); +- remove_proc_entry("i8k", NULL); +-} +- +-module_init(i8k_init); +-module_exit(i8k_exit); +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 6c94147..1c3e458 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_I8K) += dell-smm-hwmon.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c +new file mode 100644 +index 0000000..2b04e4f +--- /dev/null ++++ b/drivers/hwmon/dell-smm-hwmon.c +@@ -0,0 +1,1007 @@ ++/* ++ * dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops. ++ * ++ * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> ++ * ++ * Hwmon integration: ++ * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> ++ * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net> ++ * Copyright (C) 2014, 2015 Pali Rohár <pali.rohar@gmail.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2, or (at your option) any ++ * later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include <linux/delay.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/seq_file.h> ++#include <linux/dmi.h> ++#include <linux/capability.h> ++#include <linux/mutex.h> ++#include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/uaccess.h> ++#include <linux/io.h> ++#include <linux/sched.h> ++ ++#include <linux/i8k.h> ++ ++#define I8K_SMM_FN_STATUS 0x0025 ++#define I8K_SMM_POWER_STATUS 0x0069 ++#define I8K_SMM_SET_FAN 0x01a3 ++#define I8K_SMM_GET_FAN 0x00a3 ++#define I8K_SMM_GET_SPEED 0x02a3 ++#define I8K_SMM_GET_FAN_TYPE 0x03a3 ++#define I8K_SMM_GET_NOM_SPEED 0x04a3 ++#define I8K_SMM_GET_TEMP 0x10a3 ++#define I8K_SMM_GET_TEMP_TYPE 0x11a3 ++#define I8K_SMM_GET_DELL_SIG1 0xfea3 ++#define I8K_SMM_GET_DELL_SIG2 0xffa3 ++ ++#define I8K_FAN_MULT 30 ++#define I8K_FAN_MAX_RPM 30000 ++#define I8K_MAX_TEMP 127 ++ ++#define I8K_FN_NONE 0x00 ++#define I8K_FN_UP 0x01 ++#define I8K_FN_DOWN 0x02 ++#define I8K_FN_MUTE 0x04 ++#define I8K_FN_MASK 0x07 ++#define I8K_FN_SHIFT 8 ++ ++#define I8K_POWER_AC 0x05 ++#define I8K_POWER_BATTERY 0x01 ++ ++static DEFINE_MUTEX(i8k_mutex); ++static char bios_version[4]; ++static struct device *i8k_hwmon_dev; ++static u32 i8k_hwmon_flags; ++static uint i8k_fan_mult = I8K_FAN_MULT; ++static uint i8k_pwm_mult; ++static uint i8k_fan_max = I8K_FAN_HIGH; ++ ++#define I8K_HWMON_HAVE_TEMP1 (1 << 0) ++#define I8K_HWMON_HAVE_TEMP2 (1 << 1) ++#define I8K_HWMON_HAVE_TEMP3 (1 << 2) ++#define I8K_HWMON_HAVE_TEMP4 (1 << 3) ++#define I8K_HWMON_HAVE_FAN1 (1 << 4) ++#define I8K_HWMON_HAVE_FAN2 (1 << 5) ++ ++MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); ++MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); ++MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("i8k"); ++ ++static bool force; ++module_param(force, bool, 0); ++MODULE_PARM_DESC(force, "Force loading without checking for supported models"); ++ ++static bool ignore_dmi; ++module_param(ignore_dmi, bool, 0); ++MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); ++ ++static bool restricted; ++module_param(restricted, bool, 0); ++MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); ++ ++static bool power_status; ++module_param(power_status, bool, 0600); ++MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); ++ ++static uint fan_mult; ++module_param(fan_mult, uint, 0); ++MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)"); ++ ++static uint fan_max; ++module_param(fan_max, uint, 0); ++MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)"); ++ ++static int i8k_open_fs(struct inode *inode, struct file *file); ++static long i8k_ioctl(struct file *, unsigned int, unsigned long); ++ ++static const struct file_operations i8k_fops = { ++ .owner = THIS_MODULE, ++ .open = i8k_open_fs, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .unlocked_ioctl = i8k_ioctl, ++}; ++ ++struct smm_regs { ++ unsigned int eax; ++ unsigned int ebx __packed; ++ unsigned int ecx __packed; ++ unsigned int edx __packed; ++ unsigned int esi __packed; ++ unsigned int edi __packed; ++}; ++ ++static inline const char *i8k_get_dmi_data(int field) ++{ ++ const char *dmi_data = dmi_get_system_info(field); ++ ++ return dmi_data && *dmi_data ? dmi_data : "?"; ++} ++ ++/* ++ * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. ++ */ ++static int i8k_smm(struct smm_regs *regs) ++{ ++ int rc; ++ int eax = regs->eax; ++ cpumask_var_t old_mask; ++ ++ /* SMM requires CPU 0 */ ++ if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) ++ return -ENOMEM; ++ cpumask_copy(old_mask, ¤t->cpus_allowed); ++ rc = set_cpus_allowed_ptr(current, cpumask_of(0)); ++ if (rc) ++ goto out; ++ if (smp_processor_id() != 0) { ++ rc = -EBUSY; ++ goto out; ++ } ++ ++#if defined(CONFIG_X86_64) ++ asm volatile("pushq %%rax\n\t" ++ "movl 0(%%rax),%%edx\n\t" ++ "pushq %%rdx\n\t" ++ "movl 4(%%rax),%%ebx\n\t" ++ "movl 8(%%rax),%%ecx\n\t" ++ "movl 12(%%rax),%%edx\n\t" ++ "movl 16(%%rax),%%esi\n\t" ++ "movl 20(%%rax),%%edi\n\t" ++ "popq %%rax\n\t" ++ "out %%al,$0xb2\n\t" ++ "out %%al,$0x84\n\t" ++ "xchgq %%rax,(%%rsp)\n\t" ++ "movl %%ebx,4(%%rax)\n\t" ++ "movl %%ecx,8(%%rax)\n\t" ++ "movl %%edx,12(%%rax)\n\t" ++ "movl %%esi,16(%%rax)\n\t" ++ "movl %%edi,20(%%rax)\n\t" ++ "popq %%rdx\n\t" ++ "movl %%edx,0(%%rax)\n\t" ++ "pushfq\n\t" ++ "popq %%rax\n\t" ++ "andl $1,%%eax\n" ++ : "=a"(rc) ++ : "a"(regs) ++ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); ++#else ++ asm volatile("pushl %%eax\n\t" ++ "movl 0(%%eax),%%edx\n\t" ++ "push %%edx\n\t" ++ "movl 4(%%eax),%%ebx\n\t" ++ "movl 8(%%eax),%%ecx\n\t" ++ "movl 12(%%eax),%%edx\n\t" ++ "movl 16(%%eax),%%esi\n\t" ++ "movl 20(%%eax),%%edi\n\t" ++ "popl %%eax\n\t" ++ "out %%al,$0xb2\n\t" ++ "out %%al,$0x84\n\t" ++ "xchgl %%eax,(%%esp)\n\t" ++ "movl %%ebx,4(%%eax)\n\t" ++ "movl %%ecx,8(%%eax)\n\t" ++ "movl %%edx,12(%%eax)\n\t" ++ "movl %%esi,16(%%eax)\n\t" ++ "movl %%edi,20(%%eax)\n\t" ++ "popl %%edx\n\t" ++ "movl %%edx,0(%%eax)\n\t" ++ "lahf\n\t" ++ "shrl $8,%%eax\n\t" ++ "andl $1,%%eax\n" ++ : "=a"(rc) ++ : "a"(regs) ++ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); ++#endif ++ if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) ++ rc = -EINVAL; ++ ++out: ++ set_cpus_allowed_ptr(current, old_mask); ++ free_cpumask_var(old_mask); ++ return rc; ++} ++ ++/* ++ * Read the Fn key status. ++ */ ++static int i8k_get_fn_status(void) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; ++ int rc; ++ ++ rc = i8k_smm(®s); ++ if (rc < 0) ++ return rc; ++ ++ switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { ++ case I8K_FN_UP: ++ return I8K_VOL_UP; ++ case I8K_FN_DOWN: ++ return I8K_VOL_DOWN; ++ case I8K_FN_MUTE: ++ return I8K_VOL_MUTE; ++ default: ++ return 0; ++ } ++} ++ ++/* ++ * Read the power status. ++ */ ++static int i8k_get_power_status(void) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; ++ int rc; ++ ++ rc = i8k_smm(®s); ++ if (rc < 0) ++ return rc; ++ ++ return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; ++} ++ ++/* ++ * Read the fan status. ++ */ ++static int i8k_get_fan_status(int fan) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; ++ ++ regs.ebx = fan & 0xff; ++ return i8k_smm(®s) ? : regs.eax & 0xff; ++} ++ ++/* ++ * Read the fan speed in RPM. ++ */ ++static int i8k_get_fan_speed(int fan) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; ++ ++ regs.ebx = fan & 0xff; ++ return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; ++} ++ ++/* ++ * Read the fan type. ++ */ ++static int i8k_get_fan_type(int fan) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; ++ ++ regs.ebx = fan & 0xff; ++ return i8k_smm(®s) ? : regs.eax & 0xff; ++} ++ ++/* ++ * Read the fan nominal rpm for specific fan speed. ++ */ ++static int i8k_get_fan_nominal_speed(int fan, int speed) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; ++ ++ regs.ebx = (fan & 0xff) | (speed << 8); ++ return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; ++} ++ ++/* ++ * Set the fan speed (off, low, high). Returns the new fan status. ++ */ ++static int i8k_set_fan(int fan, int speed) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; ++ ++ speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); ++ regs.ebx = (fan & 0xff) | (speed << 8); ++ ++ return i8k_smm(®s) ? : i8k_get_fan_status(fan); ++} ++ ++static int i8k_get_temp_type(int sensor) ++{ ++ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, }; ++ ++ regs.ebx = sensor & 0xff; ++ return i8k_smm(®s) ? : regs.eax & 0xff; ++} ++ ++/* ++ * Read the cpu temperature. ++ */ ++static int _i8k_get_temp(int sensor) ++{ ++ struct smm_regs regs = { ++ .eax = I8K_SMM_GET_TEMP, ++ .ebx = sensor & 0xff, ++ }; ++ ++ return i8k_smm(®s) ? : regs.eax & 0xff; ++} ++ ++static int i8k_get_temp(int sensor) ++{ ++ int temp = _i8k_get_temp(sensor); ++ ++ /* ++ * Sometimes the temperature sensor returns 0x99, which is out of range. ++ * In this case we retry (once) before returning an error. ++ # 1003655137 00000058 00005a4b ++ # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees ++ # 1003655139 00000054 00005c52 ++ */ ++ if (temp == 0x99) { ++ msleep(100); ++ temp = _i8k_get_temp(sensor); ++ } ++ /* ++ * Return -ENODATA for all invalid temperatures. ++ * ++ * Known instances are the 0x99 value as seen above as well as ++ * 0xc1 (193), which may be returned when trying to read the GPU ++ * temperature if the system supports a GPU and it is currently ++ * turned off. ++ */ ++ if (temp > I8K_MAX_TEMP) ++ return -ENODATA; ++ ++ return temp; ++} ++ ++static int i8k_get_dell_signature(int req_fn) ++{ ++ struct smm_regs regs = { .eax = req_fn, }; ++ int rc; ++ ++ rc = i8k_smm(®s); ++ if (rc < 0) ++ return rc; ++ ++ return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; ++} ++ ++static int ++i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ int val = 0; ++ int speed; ++ unsigned char buff[16]; ++ int __user *argp = (int __user *)arg; ++ ++ if (!argp) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case I8K_BIOS_VERSION: ++ val = (bios_version[0] << 16) | ++ (bios_version[1] << 8) | bios_version[2]; ++ break; ++ ++ case I8K_MACHINE_ID: ++ memset(buff, 0, 16); ++ strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), ++ sizeof(buff)); ++ break; ++ ++ case I8K_FN_STATUS: ++ val = i8k_get_fn_status(); ++ break; ++ ++ case I8K_POWER_STATUS: ++ val = i8k_get_power_status(); ++ break; ++ ++ case I8K_GET_TEMP: ++ val = i8k_get_temp(0); ++ break; ++ ++ case I8K_GET_SPEED: ++ if (copy_from_user(&val, argp, sizeof(int))) ++ return -EFAULT; ++ ++ val = i8k_get_fan_speed(val); ++ break; ++ ++ case I8K_GET_FAN: ++ if (copy_from_user(&val, argp, sizeof(int))) ++ return -EFAULT; ++ ++ val = i8k_get_fan_status(val); ++ break; ++ ++ case I8K_SET_FAN: ++ if (restricted && !capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ if (copy_from_user(&val, argp, sizeof(int))) ++ return -EFAULT; ++ ++ if (copy_from_user(&speed, argp + 1, sizeof(int))) ++ return -EFAULT; ++ ++ val = i8k_set_fan(val, speed); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ if (val < 0) ++ return val; ++ ++ switch (cmd) { ++ case I8K_BIOS_VERSION: ++ if (copy_to_user(argp, &val, 4)) ++ return -EFAULT; ++ ++ break; ++ case I8K_MACHINE_ID: ++ if (copy_to_user(argp, buff, 16)) ++ return -EFAULT; ++ ++ break; ++ default: ++ if (copy_to_user(argp, &val, sizeof(int))) ++ return -EFAULT; ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ ++ mutex_lock(&i8k_mutex); ++ ret = i8k_ioctl_unlocked(fp, cmd, arg); ++ mutex_unlock(&i8k_mutex); ++ ++ return ret; ++} ++ ++/* ++ * Print the information for /proc/i8k. ++ */ ++static int i8k_proc_show(struct seq_file *seq, void *offset) ++{ ++ int fn_key, cpu_temp, ac_power; ++ int left_fan, right_fan, left_speed, right_speed; ++ ++ cpu_temp = i8k_get_temp(0); /* 11100 µs */ ++ left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ ++ right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ ++ left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ ++ right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ ++ fn_key = i8k_get_fn_status(); /* 750 µs */ ++ if (power_status) ++ ac_power = i8k_get_power_status(); /* 14700 µs */ ++ else ++ ac_power = -1; ++ ++ /* ++ * Info: ++ * ++ * 1) Format version (this will change if format changes) ++ * 2) BIOS version ++ * 3) BIOS machine ID ++ * 4) Cpu temperature ++ * 5) Left fan status ++ * 6) Right fan status ++ * 7) Left fan speed ++ * 8) Right fan speed ++ * 9) AC power ++ * 10) Fn Key status ++ */ ++ return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", ++ I8K_PROC_FMT, ++ bios_version, ++ i8k_get_dmi_data(DMI_PRODUCT_SERIAL), ++ cpu_temp, ++ left_fan, right_fan, left_speed, right_speed, ++ ac_power, fn_key); ++} ++ ++static int i8k_open_fs(struct inode *inode, struct file *file) ++{ ++ return single_open(file, i8k_proc_show, NULL); ++} ++ ++ ++/* ++ * Hwmon interface ++ */ ++ ++static ssize_t i8k_hwmon_show_temp_label(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ static const char * const labels[] = { ++ "CPU", ++ "GPU", ++ "SODIMM", ++ "Other", ++ "Ambient", ++ "Other", ++ }; ++ int index = to_sensor_dev_attr(devattr)->index; ++ int type; ++ ++ type = i8k_get_temp_type(index); ++ if (type < 0) ++ return type; ++ if (type >= ARRAY_SIZE(labels)) ++ type = ARRAY_SIZE(labels) - 1; ++ return sprintf(buf, "%s\n", labels[type]); ++} ++ ++static ssize_t i8k_hwmon_show_temp(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ int index = to_sensor_dev_attr(devattr)->index; ++ int temp; ++ ++ temp = i8k_get_temp(index); ++ if (temp < 0) ++ return temp; ++ return sprintf(buf, "%d\n", temp * 1000); ++} ++ ++static ssize_t i8k_hwmon_show_fan_label(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ static const char * const labels[] = { ++ "Processor Fan", ++ "Motherboard Fan", ++ "Video Fan", ++ "Power Supply Fan", ++ "Chipset Fan", ++ "Other Fan", ++ }; ++ int index = to_sensor_dev_attr(devattr)->index; ++ bool dock = false; ++ int type; ++ ++ type = i8k_get_fan_type(index); ++ if (type < 0) ++ return type; ++ ++ if (type & 0x10) { ++ dock = true; ++ type &= 0x0F; ++ } ++ ++ if (type >= ARRAY_SIZE(labels)) ++ type = (ARRAY_SIZE(labels) - 1); ++ ++ return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]); ++} ++ ++static ssize_t i8k_hwmon_show_fan(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ int index = to_sensor_dev_attr(devattr)->index; ++ int fan_speed; ++ ++ fan_speed = i8k_get_fan_speed(index); ++ if (fan_speed < 0) ++ return fan_speed; ++ return sprintf(buf, "%d\n", fan_speed); ++} ++ ++static ssize_t i8k_hwmon_show_pwm(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ int index = to_sensor_dev_attr(devattr)->index; ++ int status; ++ ++ status = i8k_get_fan_status(index); ++ if (status < 0) ++ return -EIO; ++ return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); ++} ++ ++static ssize_t i8k_hwmon_set_pwm(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int index = to_sensor_dev_attr(attr)->index; ++ unsigned long val; ++ int err; ++ ++ err = kstrtoul(buf, 10, &val); ++ if (err) ++ return err; ++ val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max); ++ ++ mutex_lock(&i8k_mutex); ++ err = i8k_set_fan(index, val); ++ mutex_unlock(&i8k_mutex); ++ ++ return err < 0 ? -EIO : count; ++} ++ ++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, ++ 0); ++static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); ++static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, ++ 1); ++static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); ++static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, ++ 2); ++static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); ++static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, ++ 3); ++static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, ++ 0); ++static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, ++ i8k_hwmon_set_pwm, 0); ++static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, ++ 1); ++static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, ++ 1); ++static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, ++ i8k_hwmon_set_pwm, 1); ++ ++static struct attribute *i8k_attrs[] = { ++ &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ ++ &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ ++ &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ ++ &sensor_dev_attr_temp2_label.dev_attr.attr, /* 3 */ ++ &sensor_dev_attr_temp3_input.dev_attr.attr, /* 4 */ ++ &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */ ++ &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ ++ &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ ++ &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ ++ &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ ++ &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ ++ &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ ++ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ ++ &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ ++ NULL ++}; ++ ++static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, ++ int index) ++{ ++ if (index >= 0 && index <= 1 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) ++ return 0; ++ if (index >= 2 && index <= 3 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) ++ return 0; ++ if (index >= 4 && index <= 5 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) ++ return 0; ++ if (index >= 6 && index <= 7 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) ++ return 0; ++ if (index >= 8 && index <= 10 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) ++ return 0; ++ if (index >= 11 && index <= 13 && ++ !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) ++ return 0; ++ ++ return attr->mode; ++} ++ ++static const struct attribute_group i8k_group = { ++ .attrs = i8k_attrs, ++ .is_visible = i8k_is_visible, ++}; ++__ATTRIBUTE_GROUPS(i8k); ++ ++static int __init i8k_init_hwmon(void) ++{ ++ int err; ++ ++ i8k_hwmon_flags = 0; ++ ++ /* CPU temperature attributes, if temperature type is OK */ ++ err = i8k_get_temp_type(0); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1; ++ /* check for additional temperature sensors */ ++ err = i8k_get_temp_type(1); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; ++ err = i8k_get_temp_type(2); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; ++ err = i8k_get_temp_type(3); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; ++ ++ /* First fan attributes, if fan type is OK */ ++ err = i8k_get_fan_type(0); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; ++ ++ /* Second fan attributes, if fan type is OK */ ++ err = i8k_get_fan_type(1); ++ if (err >= 0) ++ i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; ++ ++ i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "i8k", NULL, ++ i8k_groups); ++ if (IS_ERR(i8k_hwmon_dev)) { ++ err = PTR_ERR(i8k_hwmon_dev); ++ i8k_hwmon_dev = NULL; ++ pr_err("hwmon registration failed (%d)\n", err); ++ return err; ++ } ++ return 0; ++} ++ ++struct i8k_config_data { ++ uint fan_mult; ++ uint fan_max; ++}; ++ ++enum i8k_configs { ++ DELL_LATITUDE_D520, ++ DELL_PRECISION_490, ++ DELL_STUDIO, ++ DELL_XPS, ++}; ++ ++static const struct i8k_config_data i8k_config_data[] = { ++ [DELL_LATITUDE_D520] = { ++ .fan_mult = 1, ++ .fan_max = I8K_FAN_TURBO, ++ }, ++ [DELL_PRECISION_490] = { ++ .fan_mult = 1, ++ .fan_max = I8K_FAN_TURBO, ++ }, ++ [DELL_STUDIO] = { ++ .fan_mult = 1, ++ .fan_max = I8K_FAN_HIGH, ++ }, ++ [DELL_XPS] = { ++ .fan_mult = 1, ++ .fan_max = I8K_FAN_HIGH, ++ }, ++}; ++ ++static struct dmi_system_id i8k_dmi_table[] __initdata = { ++ { ++ .ident = "Dell Inspiron", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), ++ }, ++ }, ++ { ++ .ident = "Dell Latitude", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), ++ }, ++ }, ++ { ++ .ident = "Dell Inspiron 2", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), ++ }, ++ }, ++ { ++ .ident = "Dell Latitude D520", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"), ++ }, ++ .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], ++ }, ++ { ++ .ident = "Dell Latitude 2", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), ++ }, ++ }, ++ { /* UK Inspiron 6400 */ ++ .ident = "Dell Inspiron 3", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MM061"), ++ }, ++ }, ++ { ++ .ident = "Dell Inspiron 3", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MP061"), ++ }, ++ }, ++ { ++ .ident = "Dell Precision 490", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, ++ "Precision WorkStation 490"), ++ }, ++ .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490], ++ }, ++ { ++ .ident = "Dell Precision", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision"), ++ }, ++ }, ++ { ++ .ident = "Dell Vostro", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"), ++ }, ++ }, ++ { ++ .ident = "Dell XPS421", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), ++ }, ++ }, ++ { ++ .ident = "Dell Studio", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), ++ }, ++ .driver_data = (void *)&i8k_config_data[DELL_STUDIO], ++ }, ++ { ++ .ident = "Dell XPS 13", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"), ++ }, ++ .driver_data = (void *)&i8k_config_data[DELL_XPS], ++ }, ++ { ++ .ident = "Dell XPS M140", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), ++ }, ++ .driver_data = (void *)&i8k_config_data[DELL_XPS], ++ }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); ++ ++/* ++ * Probe for the presence of a supported laptop. ++ */ ++static int __init i8k_probe(void) ++{ ++ const struct dmi_system_id *id; ++ int fan, ret; ++ ++ /* ++ * Get DMI information ++ */ ++ if (!dmi_check_system(i8k_dmi_table)) { ++ if (!ignore_dmi && !force) ++ return -ENODEV; ++ ++ pr_info("not running on a supported Dell system.\n"); ++ pr_info("vendor=%s, model=%s, version=%s\n", ++ i8k_get_dmi_data(DMI_SYS_VENDOR), ++ i8k_get_dmi_data(DMI_PRODUCT_NAME), ++ i8k_get_dmi_data(DMI_BIOS_VERSION)); ++ } ++ ++ strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), ++ sizeof(bios_version)); ++ ++ /* ++ * Get SMM Dell signature ++ */ ++ if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && ++ i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { ++ pr_err("unable to get SMM Dell signature\n"); ++ if (!force) ++ return -ENODEV; ++ } ++ ++ /* ++ * Set fan multiplier and maximal fan speed from dmi config ++ * Values specified in module parameters override values from dmi ++ */ ++ id = dmi_first_match(i8k_dmi_table); ++ if (id && id->driver_data) { ++ const struct i8k_config_data *conf = id->driver_data; ++ if (!fan_mult && conf->fan_mult) ++ fan_mult = conf->fan_mult; ++ if (!fan_max && conf->fan_max) ++ fan_max = conf->fan_max; ++ } ++ ++ i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ ++ i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); ++ ++ if (!fan_mult) { ++ /* ++ * Autodetect fan multiplier based on nominal rpm ++ * If fan reports rpm value too high then set multiplier to 1 ++ */ ++ for (fan = 0; fan < 2; ++fan) { ++ ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max); ++ if (ret < 0) ++ continue; ++ if (ret > I8K_FAN_MAX_RPM) ++ i8k_fan_mult = 1; ++ break; ++ } ++ } else { ++ /* Fan multiplier was specified in module param or in dmi */ ++ i8k_fan_mult = fan_mult; ++ } ++ ++ return 0; ++} ++ ++static int __init i8k_init(void) ++{ ++ struct proc_dir_entry *proc_i8k; ++ int err; ++ ++ /* Are we running on an supported laptop? */ ++ if (i8k_probe()) ++ return -ENODEV; ++ ++ /* Register the proc entry */ ++ proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); ++ if (!proc_i8k) ++ return -ENOENT; ++ ++ err = i8k_init_hwmon(); ++ if (err) ++ goto exit_remove_proc; ++ ++ return 0; ++ ++ exit_remove_proc: ++ remove_proc_entry("i8k", NULL); ++ return err; ++} ++ ++static void __exit i8k_exit(void) ++{ ++ hwmon_device_unregister(i8k_hwmon_dev); ++ remove_proc_entry("i8k", NULL); ++} ++ ++module_init(i8k_init); ++module_exit(i8k_exit); +-- +1.7.9.5 diff --git a/a/content_digest b/N1/content_digest index f0ecf52..b06c53f 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,8 +1,8 @@ "ref\01427538255-10860-1-git-send-email-pali.rohar@gmail.com\0" "ref\01427633859-18596-1-git-send-email-pali.rohar@gmail.com\0" "From\0Pali Roh\303\241r <pali.rohar@gmail.com>\0" - "Subject\0[lm-sensors] [PATCH v2 1/2] hwmon: Rename i8k driver to dell-smm-hwmon and move it to hwmon tree\0" - "Date\0Sun, 29 Mar 2015 12:57:38 +0000\0" + "Subject\0[PATCH v2 1/2] hwmon: Rename i8k driver to dell-smm-hwmon and move it to hwmon tree\0" + "Date\0Sun, 29 Mar 2015 14:57:38 +0200\0" "To\0Guenter Roeck <linux@roeck-us.net>" Arnd Bergmann <arnd@arndb.de> Greg Kroah-Hartman <gregkh@linuxfoundation.org> @@ -16,929 +16,2090 @@ " Pali Roh\303\241r <pali.rohar@gmail.com>\0" "\00:1\0" "b\0" - "VGhpcyBjb21taXQgbW92ZXMgaThrIGRyaXZlciB0byBod21vbiB0cmVlIHVuZGVyIG5hbWUgZGVs\n" - "bC1zbW0taHdtb24gd2hpY2ggaXMKYmV0dGVyIG5hbWUgdGhlbiBhYmJyZXZpYXRpb24gaThrLiBG\n" - "b3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBpcyBhZGRlZCBtYWNybwpNT0RVTEVfQUxJQVMoImk4\n" - "ayIpIHNvIG1vZHByb2JlIHdpbGwgbG9hZCBkcml2ZXIgYWxzbyBvbGQgbmFtZSBpOGsuIENPTkZJ\n" - "R19JOEsKY29tcGlsZSBvcHRpb24gd2FzIG5vdCBjaGFuZ2VkLgoKVGhpcyBjb21taXQgYWxzbyBh\n" - "ZGRzIG1lIGFzIG1haW50YWluZXIgb2YgdGhpcyBuZXcgZGVsbC1zbW0taHdtb24gZHJpdmVyIGFu\n" - "ZApyZW1vdmUgR3VlbnRlciBSb2VjayBmcm9tIGxpc3Qgd2hvIGlzIGltcGxpY2l0IG1haW50YWlu\n" - "ZXIgYWxsIGh3bW9uIGRyaXZlcnMuCgpTaWduZWQtb2ZmLWJ5OiBQYWxpIFJvaMOhciA8cGFsaS5y\n" - "b2hhckBnbWFpbC5jb20+Ci0tLQogTUFJTlRBSU5FUlMgICAgICAgICAgICAgICAgICAgIHwgICAg\n" - "NCArLQogZHJpdmVycy9jaGFyL01ha2VmaWxlICAgICAgICAgIHwgICAgMSAtCiBkcml2ZXJzL2No\n" - "YXIvaThrLmMgICAgICAgICAgICAgfCAxMDA1IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t\n" - "LS0tLS0tLS0tLQogZHJpdmVycy9od21vbi9NYWtlZmlsZSAgICAgICAgIHwgICAgMSArCiBkcml2\n" - "ZXJzL2h3bW9uL2RlbGwtc21tLWh3bW9uLmMgfCAxMDA3ICsrKysrKysrKysrKysrKysrKysrKysr\n" - "KysrKysrKysrKysrKysrKysKIDUgZmlsZXMgY2hhbmdlZCwgMTAxMCBpbnNlcnRpb25zKCspLCAx\n" - "MDA4IGRlbGV0aW9ucygtKQogZGVsZXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvY2hhci9pOGsuYwog\n" - "Y3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaHdtb24vZGVsbC1zbW0taHdtb24uYwoKZGlmZiAt\n" - "LWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRBSU5FUlMKaW5kZXggODhjMDljYS4uZTU0YTA3ZSAx\n" - "MDA2NDQKLS0tIGEvTUFJTlRBSU5FUlMKKysrIGIvTUFJTlRBSU5FUlMKQEAgLTMwNjMsOSArMzA2\n" - "Myw5IEBAIFM6CU1haW50YWluZWQKIEY6CWRyaXZlcnMvcGxhdGZvcm0veDg2L2RlbGwtbGFwdG9w\n" - "LmMKIAogREVMTCBMQVBUT1AgU01NIERSSVZFUgotTToJR3VlbnRlciBSb2VjayA8bGludXhAcm9l\n" - "Y2stdXMubmV0PgorTToJUGFsaSBSb2jDoXIgPHBhbGkucm9oYXJAZ21haWwuY29tPgogUzoJTWFp\n" - "bnRhaW5lZAotRjoJZHJpdmVycy9jaGFyL2k4ay5jCitGOglkcml2ZXJzL2h3bW9uL2RlbGwtc21t\n" - "LWh3bW9uLmMKIEY6CWluY2x1ZGUvdWFwaS9saW51eC9pOGsuaAogCiBERUxMIFNZU1RFTVMgTUFO\n" - "QUdFTUVOVCBCQVNFIERSSVZFUiAoZGNkYmFzKQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL01h\n" - "a2VmaWxlIGIvZHJpdmVycy9jaGFyL01ha2VmaWxlCmluZGV4IGQwNmNkZTI2Li4xZDljZjAwIDEw\n" - "MDY0NAotLS0gYS9kcml2ZXJzL2NoYXIvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9jaGFyL01ha2Vm\n" - "aWxlCkBAIC0zNiw3ICszNiw2IEBAIGVsc2UKICAgb2JqLSQoQ09ORklHX05WUkFNKQkrPSBudnJh\n" - "bS5vCiBlbmRpZgogb2JqLSQoQ09ORklHX1RPU0hJQkEpCQkrPSB0b3NoaWJhLm8KLW9iai0kKENP\n" - "TkZJR19JOEspCQkrPSBpOGsubwogb2JqLSQoQ09ORklHX0RTMTYyMCkJCSs9IGRzMTYyMC5vCiBv\n" - "YmotJChDT05GSUdfSFdfUkFORE9NKQkJKz0gaHdfcmFuZG9tLwogb2JqLSQoQ09ORklHX1BQREVW\n" - "KQkJKz0gcHBkZXYubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2k4ay5jIGIvZHJpdmVycy9j\n" - "aGFyL2k4ay5jCmRlbGV0ZWQgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAyNGNjNGVkLi4wMDAwMDAw\n" - "Ci0tLSBhL2RyaXZlcnMvY2hhci9pOGsuYworKysgL2Rldi9udWxsCkBAIC0xLDEwMDUgKzAsMCBA\n" - "QAotLyoKLSAqIGk4ay5jIC0tIExpbnV4IGRyaXZlciBmb3IgYWNjZXNzaW5nIHRoZSBTTU0gQklP\n" - "UyBvbiBEZWxsIGxhcHRvcHMuCi0gKgotICogQ29weXJpZ2h0IChDKSAyMDAxICBNYXNzaW1vIERh\n" - "bCBab3R0byA8ZHpAZGViaWFuLm9yZz4KLSAqCi0gKiBId21vbiBpbnRlZ3JhdGlvbjoKLSAqIENv\n" - "cHlyaWdodCAoQykgMjAxMSAgSmVhbiBEZWx2YXJlIDxqZGVsdmFyZUBzdXNlLmRlPgotICogQ29w\n" - "eXJpZ2h0IChDKSAyMDEzLCAyMDE0ICBHdWVudGVyIFJvZWNrIDxsaW51eEByb2Vjay11cy5uZXQ+\n" - "Ci0gKiBDb3B5cmlnaHQgKEMpIDIwMTQgIFBhbGkgUm9ow6FyIDxwYWxpLnJvaGFyQGdtYWlsLmNv\n" - "bT4KLSAqCi0gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3Ry\n" - "aWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdAotICogdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUg\n" - "R2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlCi0gKiBGcmVlIFNvZnR3\n" - "YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55\n" - "Ci0gKiBsYXRlciB2ZXJzaW9uLgotICoKLSAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBp\n" - "biB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQKLSAqIFdJVEhPVVQgQU5ZIFdB\n" - "UlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKLSAqIE1FUkNIQU5U\n" - "QUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05V\n" - "Ci0gKiBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCi0gKi8KLQotI2Rl\n" - "ZmluZSBwcl9mbXQoZm10KSBLQlVJTERfTU9ETkFNRSAiOiAiIGZtdAotCi0jaW5jbHVkZSA8bGlu\n" - "dXgvZGVsYXkuaD4KLSNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KLSNpbmNsdWRlIDxsaW51eC90\n" - "eXBlcy5oPgotI2luY2x1ZGUgPGxpbnV4L2luaXQuaD4KLSNpbmNsdWRlIDxsaW51eC9wcm9jX2Zz\n" - "Lmg+Ci0jaW5jbHVkZSA8bGludXgvc2VxX2ZpbGUuaD4KLSNpbmNsdWRlIDxsaW51eC9kbWkuaD4K\n" - "LSNpbmNsdWRlIDxsaW51eC9jYXBhYmlsaXR5Lmg+Ci0jaW5jbHVkZSA8bGludXgvbXV0ZXguaD4K\n" - "LSNpbmNsdWRlIDxsaW51eC9od21vbi5oPgotI2luY2x1ZGUgPGxpbnV4L2h3bW9uLXN5c2ZzLmg+\n" - "Ci0jaW5jbHVkZSA8bGludXgvdWFjY2Vzcy5oPgotI2luY2x1ZGUgPGxpbnV4L2lvLmg+Ci0jaW5j\n" - "bHVkZSA8bGludXgvc2NoZWQuaD4KLQotI2luY2x1ZGUgPGxpbnV4L2k4ay5oPgotCi0jZGVmaW5l\n" - "IEk4S19TTU1fRk5fU1RBVFVTCTB4MDAyNQotI2RlZmluZSBJOEtfU01NX1BPV0VSX1NUQVRVUwkw\n" - "eDAwNjkKLSNkZWZpbmUgSThLX1NNTV9TRVRfRkFOCQkweDAxYTMKLSNkZWZpbmUgSThLX1NNTV9H\n" - "RVRfRkFOCQkweDAwYTMKLSNkZWZpbmUgSThLX1NNTV9HRVRfU1BFRUQJMHgwMmEzCi0jZGVmaW5l\n" - "IEk4S19TTU1fR0VUX0ZBTl9UWVBFCTB4MDNhMwotI2RlZmluZSBJOEtfU01NX0dFVF9OT01fU1BF\n" - "RUQJMHgwNGEzCi0jZGVmaW5lIEk4S19TTU1fR0VUX1RFTVAJMHgxMGEzCi0jZGVmaW5lIEk4S19T\n" - "TU1fR0VUX1RFTVBfVFlQRQkweDExYTMKLSNkZWZpbmUgSThLX1NNTV9HRVRfREVMTF9TSUcxCTB4\n" - "ZmVhMwotI2RlZmluZSBJOEtfU01NX0dFVF9ERUxMX1NJRzIJMHhmZmEzCi0KLSNkZWZpbmUgSThL\n" - "X0ZBTl9NVUxUCQkzMAotI2RlZmluZSBJOEtfRkFOX01BWF9SUE0JCTMwMDAwCi0jZGVmaW5lIEk4\n" - "S19NQVhfVEVNUAkJMTI3Ci0KLSNkZWZpbmUgSThLX0ZOX05PTkUJCTB4MDAKLSNkZWZpbmUgSThL\n" - "X0ZOX1VQCQkweDAxCi0jZGVmaW5lIEk4S19GTl9ET1dOCQkweDAyCi0jZGVmaW5lIEk4S19GTl9N\n" - "VVRFCQkweDA0Ci0jZGVmaW5lIEk4S19GTl9NQVNLCQkweDA3Ci0jZGVmaW5lIEk4S19GTl9TSElG\n" - "VAkJOAotCi0jZGVmaW5lIEk4S19QT1dFUl9BQwkJMHgwNQotI2RlZmluZSBJOEtfUE9XRVJfQkFU\n" - "VEVSWQkweDAxCi0KLXN0YXRpYyBERUZJTkVfTVVURVgoaThrX211dGV4KTsKLXN0YXRpYyBjaGFy\n" - "IGJpb3NfdmVyc2lvbls0XTsKLXN0YXRpYyBzdHJ1Y3QgZGV2aWNlICppOGtfaHdtb25fZGV2Owot\n" - "c3RhdGljIHUzMiBpOGtfaHdtb25fZmxhZ3M7Ci1zdGF0aWMgdWludCBpOGtfZmFuX211bHQgPSBJ\n" - "OEtfRkFOX01VTFQ7Ci1zdGF0aWMgdWludCBpOGtfcHdtX211bHQ7Ci1zdGF0aWMgdWludCBpOGtf\n" - "ZmFuX21heCA9IEk4S19GQU5fSElHSDsKLQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1QMQko\n" - "MSA8PCAwKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1QMgkoMSA8PCAxKQotI2RlZmluZSBJ\n" - "OEtfSFdNT05fSEFWRV9URU1QMwkoMSA8PCAyKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9URU1Q\n" - "NAkoMSA8PCAzKQotI2RlZmluZSBJOEtfSFdNT05fSEFWRV9GQU4xCSgxIDw8IDQpCi0jZGVmaW5l\n" - "IEk4S19IV01PTl9IQVZFX0ZBTjIJKDEgPDwgNSkKLQotTU9EVUxFX0FVVEhPUigiTWFzc2ltbyBE\n" - "YWwgWm90dG8gKGR6QGRlYmlhbi5vcmcpIik7Ci1NT0RVTEVfREVTQ1JJUFRJT04oIkRyaXZlciBm\n" - "b3IgYWNjZXNzaW5nIFNNTSBCSU9TIG9uIERlbGwgbGFwdG9wcyIpOwotTU9EVUxFX0xJQ0VOU0Uo\n" - "IkdQTCIpOwotCi1zdGF0aWMgYm9vbCBmb3JjZTsKLW1vZHVsZV9wYXJhbShmb3JjZSwgYm9vbCwg\n" - "MCk7Ci1NT0RVTEVfUEFSTV9ERVNDKGZvcmNlLCAiRm9yY2UgbG9hZGluZyB3aXRob3V0IGNoZWNr\n" - "aW5nIGZvciBzdXBwb3J0ZWQgbW9kZWxzIik7Ci0KLXN0YXRpYyBib29sIGlnbm9yZV9kbWk7Ci1t\n" - "b2R1bGVfcGFyYW0oaWdub3JlX2RtaSwgYm9vbCwgMCk7Ci1NT0RVTEVfUEFSTV9ERVNDKGlnbm9y\n" - "ZV9kbWksICJDb250aW51ZSBwcm9iaW5nIGhhcmR3YXJlIGV2ZW4gaWYgRE1JIGRhdGEgZG9lcyBu\n" - "b3QgbWF0Y2giKTsKLQotc3RhdGljIGJvb2wgcmVzdHJpY3RlZDsKLW1vZHVsZV9wYXJhbShyZXN0\n" - "cmljdGVkLCBib29sLCAwKTsKLU1PRFVMRV9QQVJNX0RFU0MocmVzdHJpY3RlZCwgIkFsbG93IGZh\n" - "biBjb250cm9sIGlmIFNZU19BRE1JTiBjYXBhYmlsaXR5IHNldCIpOwotCi1zdGF0aWMgYm9vbCBw\n" - "b3dlcl9zdGF0dXM7Ci1tb2R1bGVfcGFyYW0ocG93ZXJfc3RhdHVzLCBib29sLCAwNjAwKTsKLU1P\n" - "RFVMRV9QQVJNX0RFU0MocG93ZXJfc3RhdHVzLCAiUmVwb3J0IHBvd2VyIHN0YXR1cyBpbiAvcHJv\n" - "Yy9pOGsiKTsKLQotc3RhdGljIHVpbnQgZmFuX211bHQ7Ci1tb2R1bGVfcGFyYW0oZmFuX211bHQs\n" - "IHVpbnQsIDApOwotTU9EVUxFX1BBUk1fREVTQyhmYW5fbXVsdCwgIkZhY3RvciB0byBtdWx0aXBs\n" - "eSBmYW4gc3BlZWQgd2l0aCAoZGVmYXVsdDogYXV0b2RldGVjdCkiKTsKLQotc3RhdGljIHVpbnQg\n" - "ZmFuX21heDsKLW1vZHVsZV9wYXJhbShmYW5fbWF4LCB1aW50LCAwKTsKLU1PRFVMRV9QQVJNX0RF\n" - "U0MoZmFuX21heCwgIk1heGltdW0gY29uZmlndXJhYmxlIGZhbiBzcGVlZCAoZGVmYXVsdDogYXV0\n" - "b2RldGVjdCkiKTsKLQotc3RhdGljIGludCBpOGtfb3Blbl9mcyhzdHJ1Y3QgaW5vZGUgKmlub2Rl\n" - "LCBzdHJ1Y3QgZmlsZSAqZmlsZSk7Ci1zdGF0aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUg\n" - "KiwgdW5zaWduZWQgaW50LCB1bnNpZ25lZCBsb25nKTsKLQotc3RhdGljIGNvbnN0IHN0cnVjdCBm\n" - "aWxlX29wZXJhdGlvbnMgaThrX2ZvcHMgPSB7Ci0JLm93bmVyCQk9IFRISVNfTU9EVUxFLAotCS5v\n" - "cGVuCQk9IGk4a19vcGVuX2ZzLAotCS5yZWFkCQk9IHNlcV9yZWFkLAotCS5sbHNlZWsJCT0gc2Vx\n" - "X2xzZWVrLAotCS5yZWxlYXNlCT0gc2luZ2xlX3JlbGVhc2UsCi0JLnVubG9ja2VkX2lvY3RsCT0g\n" - "aThrX2lvY3RsLAotfTsKLQotc3RydWN0IHNtbV9yZWdzIHsKLQl1bnNpZ25lZCBpbnQgZWF4Owot\n" - "CXVuc2lnbmVkIGludCBlYnggX19wYWNrZWQ7Ci0JdW5zaWduZWQgaW50IGVjeCBfX3BhY2tlZDsK\n" - "LQl1bnNpZ25lZCBpbnQgZWR4IF9fcGFja2VkOwotCXVuc2lnbmVkIGludCBlc2kgX19wYWNrZWQ7\n" - "Ci0JdW5zaWduZWQgaW50IGVkaSBfX3BhY2tlZDsKLX07Ci0KLXN0YXRpYyBpbmxpbmUgY29uc3Qg\n" - "Y2hhciAqaThrX2dldF9kbWlfZGF0YShpbnQgZmllbGQpCi17Ci0JY29uc3QgY2hhciAqZG1pX2Rh\n" - "dGEgPSBkbWlfZ2V0X3N5c3RlbV9pbmZvKGZpZWxkKTsKLQotCXJldHVybiBkbWlfZGF0YSAmJiAq\n" - "ZG1pX2RhdGEgPyBkbWlfZGF0YSA6ICI/IjsKLX0KLQotLyoKLSAqIENhbGwgdGhlIFN5c3RlbSBN\n" - "YW5hZ2VtZW50IE1vZGUgQklPUy4gQ29kZSBwcm92aWRlZCBieSBKb25hdGhhbiBCdXp6YXJkLgot\n" - "ICovCi1zdGF0aWMgaW50IGk4a19zbW0oc3RydWN0IHNtbV9yZWdzICpyZWdzKQotewotCWludCBy\n" - "YzsKLQlpbnQgZWF4ID0gcmVncy0+ZWF4OwotCWNwdW1hc2tfdmFyX3Qgb2xkX21hc2s7Ci0KLQkv\n" - "KiBTTU0gcmVxdWlyZXMgQ1BVIDAgKi8KLQlpZiAoIWFsbG9jX2NwdW1hc2tfdmFyKCZvbGRfbWFz\n" - "aywgR0ZQX0tFUk5FTCkpCi0JCXJldHVybiAtRU5PTUVNOwotCWNwdW1hc2tfY29weShvbGRfbWFz\n" - "aywgJmN1cnJlbnQtPmNwdXNfYWxsb3dlZCk7Ci0JcmMgPSBzZXRfY3B1c19hbGxvd2VkX3B0cihj\n" - "dXJyZW50LCBjcHVtYXNrX29mKDApKTsKLQlpZiAocmMpCi0JCWdvdG8gb3V0OwotCWlmIChzbXBf\n" - "cHJvY2Vzc29yX2lkKCkgIT0gMCkgewotCQlyYyA9IC1FQlVTWTsKLQkJZ290byBvdXQ7Ci0JfQot\n" - "Ci0jaWYgZGVmaW5lZChDT05GSUdfWDg2XzY0KQotCWFzbSB2b2xhdGlsZSgicHVzaHEgJSVyYXhc\n" - "blx0IgotCQkibW92bCAwKCUlcmF4KSwlJWVkeFxuXHQiCi0JCSJwdXNocSAlJXJkeFxuXHQiCi0J\n" - "CSJtb3ZsIDQoJSVyYXgpLCUlZWJ4XG5cdCIKLQkJIm1vdmwgOCglJXJheCksJSVlY3hcblx0Igot\n" - "CQkibW92bCAxMiglJXJheCksJSVlZHhcblx0IgotCQkibW92bCAxNiglJXJheCksJSVlc2lcblx0\n" - "IgotCQkibW92bCAyMCglJXJheCksJSVlZGlcblx0IgotCQkicG9wcSAlJXJheFxuXHQiCi0JCSJv\n" - "dXQgJSVhbCwkMHhiMlxuXHQiCi0JCSJvdXQgJSVhbCwkMHg4NFxuXHQiCi0JCSJ4Y2hncSAlJXJh\n" - "eCwoJSVyc3ApXG5cdCIKLQkJIm1vdmwgJSVlYngsNCglJXJheClcblx0IgotCQkibW92bCAlJWVj\n" - "eCw4KCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUlZWR4LDEyKCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUl\n" - "ZXNpLDE2KCUlcmF4KVxuXHQiCi0JCSJtb3ZsICUlZWRpLDIwKCUlcmF4KVxuXHQiCi0JCSJwb3Bx\n" - "ICUlcmR4XG5cdCIKLQkJIm1vdmwgJSVlZHgsMCglJXJheClcblx0IgotCQkicHVzaGZxXG5cdCIK\n" - "LQkJInBvcHEgJSVyYXhcblx0IgotCQkiYW5kbCAkMSwlJWVheFxuIgotCQk6ICI9YSIocmMpCi0J\n" - "CTogICAgImEiKHJlZ3MpCi0JCTogICAgIiVlYngiLCAiJWVjeCIsICIlZWR4IiwgIiVlc2kiLCAi\n" - "JWVkaSIsICJtZW1vcnkiKTsKLSNlbHNlCi0JYXNtIHZvbGF0aWxlKCJwdXNobCAlJWVheFxuXHQi\n" - "Ci0JICAgICJtb3ZsIDAoJSVlYXgpLCUlZWR4XG5cdCIKLQkgICAgInB1c2ggJSVlZHhcblx0Igot\n" - "CSAgICAibW92bCA0KCUlZWF4KSwlJWVieFxuXHQiCi0JICAgICJtb3ZsIDgoJSVlYXgpLCUlZWN4\n" - "XG5cdCIKLQkgICAgIm1vdmwgMTIoJSVlYXgpLCUlZWR4XG5cdCIKLQkgICAgIm1vdmwgMTYoJSVl\n" - "YXgpLCUlZXNpXG5cdCIKLQkgICAgIm1vdmwgMjAoJSVlYXgpLCUlZWRpXG5cdCIKLQkgICAgInBv\n" - "cGwgJSVlYXhcblx0IgotCSAgICAib3V0ICUlYWwsJDB4YjJcblx0IgotCSAgICAib3V0ICUlYWws\n" - "JDB4ODRcblx0IgotCSAgICAieGNoZ2wgJSVlYXgsKCUlZXNwKVxuXHQiCi0JICAgICJtb3ZsICUl\n" - "ZWJ4LDQoJSVlYXgpXG5cdCIKLQkgICAgIm1vdmwgJSVlY3gsOCglJWVheClcblx0IgotCSAgICAi\n" - "bW92bCAlJWVkeCwxMiglJWVheClcblx0IgotCSAgICAibW92bCAlJWVzaSwxNiglJWVheClcblx0\n" - "IgotCSAgICAibW92bCAlJWVkaSwyMCglJWVheClcblx0IgotCSAgICAicG9wbCAlJWVkeFxuXHQi\n" - "Ci0JICAgICJtb3ZsICUlZWR4LDAoJSVlYXgpXG5cdCIKLQkgICAgImxhaGZcblx0IgotCSAgICAi\n" - "c2hybCAkOCwlJWVheFxuXHQiCi0JICAgICJhbmRsICQxLCUlZWF4XG4iCi0JICAgIDogIj1hIihy\n" - "YykKLQkgICAgOiAgICAiYSIocmVncykKLQkgICAgOiAgICAiJWVieCIsICIlZWN4IiwgIiVlZHgi\n" - "LCAiJWVzaSIsICIlZWRpIiwgIm1lbW9yeSIpOwotI2VuZGlmCi0JaWYgKHJjICE9IDAgfHwgKHJl\n" - "Z3MtPmVheCAmIDB4ZmZmZikgPT0gMHhmZmZmIHx8IHJlZ3MtPmVheCA9PSBlYXgpCi0JCXJjID0g\n" - "LUVJTlZBTDsKLQotb3V0OgotCXNldF9jcHVzX2FsbG93ZWRfcHRyKGN1cnJlbnQsIG9sZF9tYXNr\n" - "KTsKLQlmcmVlX2NwdW1hc2tfdmFyKG9sZF9tYXNrKTsKLQlyZXR1cm4gcmM7Ci19Ci0KLS8qCi0g\n" - "KiBSZWFkIHRoZSBGbiBrZXkgc3RhdHVzLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZm5fc3Rh\n" - "dHVzKHZvaWQpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0ZO\n" - "X1NUQVRVUywgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0oJnJlZ3MpOwotCWlmIChyYyA8\n" - "IDApCi0JCXJldHVybiByYzsKLQotCXN3aXRjaCAoKHJlZ3MuZWF4ID4+IEk4S19GTl9TSElGVCkg\n" - "JiBJOEtfRk5fTUFTSykgewotCWNhc2UgSThLX0ZOX1VQOgotCQlyZXR1cm4gSThLX1ZPTF9VUDsK\n" - "LQljYXNlIEk4S19GTl9ET1dOOgotCQlyZXR1cm4gSThLX1ZPTF9ET1dOOwotCWNhc2UgSThLX0ZO\n" - "X01VVEU6Ci0JCXJldHVybiBJOEtfVk9MX01VVEU7Ci0JZGVmYXVsdDoKLQkJcmV0dXJuIDA7Ci0J\n" - "fQotfQotCi0vKgotICogUmVhZCB0aGUgcG93ZXIgc3RhdHVzLgotICovCi1zdGF0aWMgaW50IGk4\n" - "a19nZXRfcG93ZXJfc3RhdHVzKHZvaWQpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5l\n" - "YXggPSBJOEtfU01NX1BPV0VSX1NUQVRVUywgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0o\n" - "JnJlZ3MpOwotCWlmIChyYyA8IDApCi0JCXJldHVybiByYzsKLQotCXJldHVybiAocmVncy5lYXgg\n" - "JiAweGZmKSA9PSBJOEtfUE9XRVJfQUMgPyBJOEtfQUMgOiBJOEtfQkFUVEVSWTsKLX0KLQotLyoK\n" - "LSAqIFJlYWQgdGhlIGZhbiBzdGF0dXMuCi0gKi8KLXN0YXRpYyBpbnQgaThrX2dldF9mYW5fc3Rh\n" - "dHVzKGludCBmYW4pCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01N\n" - "X0dFVF9GQU4sIH07Ci0KLQlyZWdzLmVieCA9IGZhbiAmIDB4ZmY7Ci0JcmV0dXJuIGk4a19zbW0o\n" - "JnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Ci19Ci0KLS8qCi0gKiBSZWFkIHRoZSBmYW4gc3Bl\n" - "ZWQgaW4gUlBNLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZmFuX3NwZWVkKGludCBmYW4pCi17\n" - "Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9TUEVFRCwgfTsK\n" - "LQotCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKLQlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IChy\n" - "ZWdzLmVheCAmIDB4ZmZmZikgKiBpOGtfZmFuX211bHQ7Ci19Ci0KLS8qCi0gKiBSZWFkIHRoZSBm\n" - "YW4gdHlwZS4KLSAqLwotc3RhdGljIGludCBpOGtfZ2V0X2Zhbl90eXBlKGludCBmYW4pCi17Ci0J\n" - "c3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9GQU5fVFlQRSwgfTsK\n" - "LQotCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKLQlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IHJl\n" - "Z3MuZWF4ICYgMHhmZjsKLX0KLQotLyoKLSAqIFJlYWQgdGhlIGZhbiBub21pbmFsIHJwbSBmb3Ig\n" - "c3BlY2lmaWMgZmFuIHNwZWVkLgotICovCi1zdGF0aWMgaW50IGk4a19nZXRfZmFuX25vbWluYWxf\n" - "c3BlZWQoaW50IGZhbiwgaW50IHNwZWVkKQotewotCXN0cnVjdCBzbW1fcmVncyByZWdzID0geyAu\n" - "ZWF4ID0gSThLX1NNTV9HRVRfTk9NX1NQRUVELCB9OwotCi0JcmVncy5lYnggPSAoZmFuICYgMHhm\n" - "ZikgfCAoc3BlZWQgPDwgOCk7Ci0JcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiAocmVncy5lYXgg\n" - "JiAweGZmZmYpICogaThrX2Zhbl9tdWx0OwotfQotCi0vKgotICogU2V0IHRoZSBmYW4gc3BlZWQg\n" - "KG9mZiwgbG93LCBoaWdoKS4gUmV0dXJucyB0aGUgbmV3IGZhbiBzdGF0dXMuCi0gKi8KLXN0YXRp\n" - "YyBpbnQgaThrX3NldF9mYW4oaW50IGZhbiwgaW50IHNwZWVkKQotewotCXN0cnVjdCBzbW1fcmVn\n" - "cyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9TRVRfRkFOLCB9OwotCi0Jc3BlZWQgPSAoc3BlZWQg\n" - "PCAwKSA/IDAgOiAoKHNwZWVkID4gaThrX2Zhbl9tYXgpID8gaThrX2Zhbl9tYXggOiBzcGVlZCk7\n" - "Ci0JcmVncy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwgOCk7Ci0KLQlyZXR1cm4gaThr\n" - "X3NtbSgmcmVncykgPyA6IGk4a19nZXRfZmFuX3N0YXR1cyhmYW4pOwotfQotCi1zdGF0aWMgaW50\n" - "IGk4a19nZXRfdGVtcF90eXBlKGludCBzZW5zb3IpCi17Ci0Jc3RydWN0IHNtbV9yZWdzIHJlZ3Mg\n" - "PSB7IC5lYXggPSBJOEtfU01NX0dFVF9URU1QX1RZUEUsIH07Ci0KLQlyZWdzLmVieCA9IHNlbnNv\n" - "ciAmIDB4ZmY7Ci0JcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Ci19\n" - "Ci0KLS8qCi0gKiBSZWFkIHRoZSBjcHUgdGVtcGVyYXR1cmUuCi0gKi8KLXN0YXRpYyBpbnQgX2k4\n" - "a19nZXRfdGVtcChpbnQgc2Vuc29yKQotewotCXN0cnVjdCBzbW1fcmVncyByZWdzID0gewotCQku\n" - "ZWF4ID0gSThLX1NNTV9HRVRfVEVNUCwKLQkJLmVieCA9IHNlbnNvciAmIDB4ZmYsCi0JfTsKLQot\n" - "CXJldHVybiBpOGtfc21tKCZyZWdzKSA/IDogcmVncy5lYXggJiAweGZmOwotfQotCi1zdGF0aWMg\n" - "aW50IGk4a19nZXRfdGVtcChpbnQgc2Vuc29yKQotewotCWludCB0ZW1wID0gX2k4a19nZXRfdGVt\n" - "cChzZW5zb3IpOwotCi0JLyoKLQkgKiBTb21ldGltZXMgdGhlIHRlbXBlcmF0dXJlIHNlbnNvciBy\n" - "ZXR1cm5zIDB4OTksIHdoaWNoIGlzIG91dCBvZiByYW5nZS4KLQkgKiBJbiB0aGlzIGNhc2Ugd2Ug\n" - "cmV0cnkgKG9uY2UpIGJlZm9yZSByZXR1cm5pbmcgYW4gZXJyb3IuCi0JICMgMTAwMzY1NTEzNyAw\n" - "MDAwMDA1OCAwMDAwNWE0YgotCSAjIDEwMDM2NTUxMzggMDAwMDAwOTkgMDAwMDNhODAgPC0tLSAw\n" - "eDk5ID0gMTUzIGRlZ3JlZXMKLQkgIyAxMDAzNjU1MTM5IDAwMDAwMDU0IDAwMDA1YzUyCi0JICov\n" - "Ci0JaWYgKHRlbXAgPT0gMHg5OSkgewotCQltc2xlZXAoMTAwKTsKLQkJdGVtcCA9IF9pOGtfZ2V0\n" - "X3RlbXAoc2Vuc29yKTsKLQl9Ci0JLyoKLQkgKiBSZXR1cm4gLUVOT0RBVEEgZm9yIGFsbCBpbnZh\n" - "bGlkIHRlbXBlcmF0dXJlcy4KLQkgKgotCSAqIEtub3duIGluc3RhbmNlcyBhcmUgdGhlIDB4OTkg\n" - "dmFsdWUgYXMgc2VlbiBhYm92ZSBhcyB3ZWxsIGFzCi0JICogMHhjMSAoMTkzKSwgd2hpY2ggbWF5\n" - "IGJlIHJldHVybmVkIHdoZW4gdHJ5aW5nIHRvIHJlYWQgdGhlIEdQVQotCSAqIHRlbXBlcmF0dXJl\n" - "IGlmIHRoZSBzeXN0ZW0gc3VwcG9ydHMgYSBHUFUgYW5kIGl0IGlzIGN1cnJlbnRseQotCSAqIHR1\n" - "cm5lZCBvZmYuCi0JICovCi0JaWYgKHRlbXAgPiBJOEtfTUFYX1RFTVApCi0JCXJldHVybiAtRU5P\n" - "REFUQTsKLQotCXJldHVybiB0ZW1wOwotfQotCi1zdGF0aWMgaW50IGk4a19nZXRfZGVsbF9zaWdu\n" - "YXR1cmUoaW50IHJlcV9mbikKLXsKLQlzdHJ1Y3Qgc21tX3JlZ3MgcmVncyA9IHsgLmVheCA9IHJl\n" - "cV9mbiwgfTsKLQlpbnQgcmM7Ci0KLQlyYyA9IGk4a19zbW0oJnJlZ3MpOwotCWlmIChyYyA8IDAp\n" - "Ci0JCXJldHVybiByYzsKLQotCXJldHVybiByZWdzLmVheCA9PSAxMTQ1NjUxNTI3ICYmIHJlZ3Mu\n" - "ZWR4ID09IDExNDUzOTIyMDQgPyAwIDogLTE7Ci19Ci0KLXN0YXRpYyBpbnQKLWk4a19pb2N0bF91\n" - "bmxvY2tlZChzdHJ1Y3QgZmlsZSAqZnAsIHVuc2lnbmVkIGludCBjbWQsIHVuc2lnbmVkIGxvbmcg\n" - "YXJnKQotewotCWludCB2YWwgPSAwOwotCWludCBzcGVlZDsKLQl1bnNpZ25lZCBjaGFyIGJ1ZmZb\n" - "MTZdOwotCWludCBfX3VzZXIgKmFyZ3AgPSAoaW50IF9fdXNlciAqKWFyZzsKLQotCWlmICghYXJn\n" - "cCkKLQkJcmV0dXJuIC1FSU5WQUw7Ci0KLQlzd2l0Y2ggKGNtZCkgewotCWNhc2UgSThLX0JJT1Nf\n" - "VkVSU0lPTjoKLQkJdmFsID0gKGJpb3NfdmVyc2lvblswXSA8PCAxNikgfAotCQkJCShiaW9zX3Zl\n" - "cnNpb25bMV0gPDwgOCkgfCBiaW9zX3ZlcnNpb25bMl07Ci0JCWJyZWFrOwotCi0JY2FzZSBJOEtf\n" - "TUFDSElORV9JRDoKLQkJbWVtc2V0KGJ1ZmYsIDAsIDE2KTsKLQkJc3RybGNweShidWZmLCBpOGtf\n" - "Z2V0X2RtaV9kYXRhKERNSV9QUk9EVUNUX1NFUklBTCksCi0JCQlzaXplb2YoYnVmZikpOwotCQli\n" - "cmVhazsKLQotCWNhc2UgSThLX0ZOX1NUQVRVUzoKLQkJdmFsID0gaThrX2dldF9mbl9zdGF0dXMo\n" - "KTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19QT1dFUl9TVEFUVVM6Ci0JCXZhbCA9IGk4a19nZXRf\n" - "cG93ZXJfc3RhdHVzKCk7Ci0JCWJyZWFrOwotCi0JY2FzZSBJOEtfR0VUX1RFTVA6Ci0JCXZhbCA9\n" - "IGk4a19nZXRfdGVtcCgwKTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19HRVRfU1BFRUQ6Ci0JCWlm\n" - "IChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2YoaW50KSkpCi0JCQlyZXR1cm4gLUVG\n" - "QVVMVDsKLQotCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zcGVlZCh2YWwpOwotCQlicmVhazsKLQotCWNh\n" - "c2UgSThLX0dFVF9GQU46Ci0JCWlmIChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2Yo\n" - "aW50KSkpCi0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zdGF0dXMo\n" - "dmFsKTsKLQkJYnJlYWs7Ci0KLQljYXNlIEk4S19TRVRfRkFOOgotCQlpZiAocmVzdHJpY3RlZCAm\n" - "JiAhY2FwYWJsZShDQVBfU1lTX0FETUlOKSkKLQkJCXJldHVybiAtRVBFUk07Ci0KLQkJaWYgKGNv\n" - "cHlfZnJvbV91c2VyKCZ2YWwsIGFyZ3AsIHNpemVvZihpbnQpKSkKLQkJCXJldHVybiAtRUZBVUxU\n" - "OwotCi0JCWlmIChjb3B5X2Zyb21fdXNlcigmc3BlZWQsIGFyZ3AgKyAxLCBzaXplb2YoaW50KSkp\n" - "Ci0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQl2YWwgPSBpOGtfc2V0X2Zhbih2YWwsIHNwZWVkKTsK\n" - "LQkJYnJlYWs7Ci0KLQlkZWZhdWx0OgotCQlyZXR1cm4gLUVJTlZBTDsKLQl9Ci0KLQlpZiAodmFs\n" - "IDwgMCkKLQkJcmV0dXJuIHZhbDsKLQotCXN3aXRjaCAoY21kKSB7Ci0JY2FzZSBJOEtfQklPU19W\n" - "RVJTSU9OOgotCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWwsIDQpKQotCQkJcmV0dXJuIC1F\n" - "RkFVTFQ7Ci0KLQkJYnJlYWs7Ci0JY2FzZSBJOEtfTUFDSElORV9JRDoKLQkJaWYgKGNvcHlfdG9f\n" - "dXNlcihhcmdwLCBidWZmLCAxNikpCi0JCQlyZXR1cm4gLUVGQVVMVDsKLQotCQlicmVhazsKLQlk\n" - "ZWZhdWx0OgotCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWwsIHNpemVvZihpbnQpKSkKLQkJ\n" - "CXJldHVybiAtRUZBVUxUOwotCi0JCWJyZWFrOwotCX0KLQotCXJldHVybiAwOwotfQotCi1zdGF0\n" - "aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUgKmZwLCB1bnNpZ25lZCBpbnQgY21kLCB1bnNp\n" - "Z25lZCBsb25nIGFyZykKLXsKLQlsb25nIHJldDsKLQotCW11dGV4X2xvY2soJmk4a19tdXRleCk7\n" - "Ci0JcmV0ID0gaThrX2lvY3RsX3VubG9ja2VkKGZwLCBjbWQsIGFyZyk7Ci0JbXV0ZXhfdW5sb2Nr\n" - "KCZpOGtfbXV0ZXgpOwotCi0JcmV0dXJuIHJldDsKLX0KLQotLyoKLSAqIFByaW50IHRoZSBpbmZv\n" - "cm1hdGlvbiBmb3IgL3Byb2MvaThrLgotICovCi1zdGF0aWMgaW50IGk4a19wcm9jX3Nob3coc3Ry\n" - "dWN0IHNlcV9maWxlICpzZXEsIHZvaWQgKm9mZnNldCkKLXsKLQlpbnQgZm5fa2V5LCBjcHVfdGVt\n" - "cCwgYWNfcG93ZXI7Ci0JaW50IGxlZnRfZmFuLCByaWdodF9mYW4sIGxlZnRfc3BlZWQsIHJpZ2h0\n" - "X3NwZWVkOwotCi0JY3B1X3RlbXAJPSBpOGtfZ2V0X3RlbXAoMCk7CQkJLyogMTExMDAgwrVzICov\n" - "Ci0JbGVmdF9mYW4JPSBpOGtfZ2V0X2Zhbl9zdGF0dXMoSThLX0ZBTl9MRUZUKTsJLyogICA1ODAg\n" - "wrVzICovCi0JcmlnaHRfZmFuCT0gaThrX2dldF9mYW5fc3RhdHVzKEk4S19GQU5fUklHSFQpOwkv\n" - "KiAgIDU4MCDCtXMgKi8KLQlsZWZ0X3NwZWVkCT0gaThrX2dldF9mYW5fc3BlZWQoSThLX0ZBTl9M\n" - "RUZUKTsJLyogICA1ODAgwrVzICovCi0JcmlnaHRfc3BlZWQJPSBpOGtfZ2V0X2Zhbl9zcGVlZChJ\n" - "OEtfRkFOX1JJR0hUKTsJLyogICA1ODAgwrVzICovCi0JZm5fa2V5CQk9IGk4a19nZXRfZm5fc3Rh\n" - "dHVzKCk7CQkJLyogICA3NTAgwrVzICovCi0JaWYgKHBvd2VyX3N0YXR1cykKLQkJYWNfcG93ZXIg\n" - "PSBpOGtfZ2V0X3Bvd2VyX3N0YXR1cygpOwkJLyogMTQ3MDAgwrVzICovCi0JZWxzZQotCQlhY19w\n" - "b3dlciA9IC0xOwotCi0JLyoKLQkgKiBJbmZvOgotCSAqCi0JICogMSkgIEZvcm1hdCB2ZXJzaW9u\n" - "ICh0aGlzIHdpbGwgY2hhbmdlIGlmIGZvcm1hdCBjaGFuZ2VzKQotCSAqIDIpICBCSU9TIHZlcnNp\n" - "b24KLQkgKiAzKSAgQklPUyBtYWNoaW5lIElECi0JICogNCkgIENwdSB0ZW1wZXJhdHVyZQotCSAq\n" - "IDUpICBMZWZ0IGZhbiBzdGF0dXMKLQkgKiA2KSAgUmlnaHQgZmFuIHN0YXR1cwotCSAqIDcpICBM\n" - "ZWZ0IGZhbiBzcGVlZAotCSAqIDgpICBSaWdodCBmYW4gc3BlZWQKLQkgKiA5KSAgQUMgcG93ZXIK\n" - "LQkgKiAxMCkgRm4gS2V5IHN0YXR1cwotCSAqLwotCXJldHVybiBzZXFfcHJpbnRmKHNlcSwgIiVz\n" - "ICVzICVzICVkICVkICVkICVkICVkICVkICVkXG4iLAotCQkJICBJOEtfUFJPQ19GTVQsCi0JCQkg\n" - "IGJpb3NfdmVyc2lvbiwKLQkJCSAgaThrX2dldF9kbWlfZGF0YShETUlfUFJPRFVDVF9TRVJJQUwp\n" - "LAotCQkJICBjcHVfdGVtcCwKLQkJCSAgbGVmdF9mYW4sIHJpZ2h0X2ZhbiwgbGVmdF9zcGVlZCwg\n" - "cmlnaHRfc3BlZWQsCi0JCQkgIGFjX3Bvd2VyLCBmbl9rZXkpOwotfQotCi1zdGF0aWMgaW50IGk4\n" - "a19vcGVuX2ZzKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpmaWxlKQotewotCXJl\n" - "dHVybiBzaW5nbGVfb3BlbihmaWxlLCBpOGtfcHJvY19zaG93LCBOVUxMKTsKLX0KLQotCi0vKgot\n" - "ICogSHdtb24gaW50ZXJmYWNlCi0gKi8KLQotc3RhdGljIHNzaXplX3QgaThrX2h3bW9uX3Nob3df\n" - "dGVtcF9sYWJlbChzdHJ1Y3QgZGV2aWNlICpkZXYsCi0JCQkJCSBzdHJ1Y3QgZGV2aWNlX2F0dHJp\n" - "YnV0ZSAqZGV2YXR0ciwKLQkJCQkJIGNoYXIgKmJ1ZikKLXsKLQlzdGF0aWMgY29uc3QgY2hhciAq\n" - "IGNvbnN0IGxhYmVsc1tdID0gewotCQkiQ1BVIiwKLQkJIkdQVSIsCi0JCSJTT0RJTU0iLAotCQki\n" - "T3RoZXIiLAotCQkiQW1iaWVudCIsCi0JCSJPdGhlciIsCi0JfTsKLQlpbnQgaW5kZXggPSB0b19z\n" - "ZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4OwotCWludCB0eXBlOwotCi0JdHlwZSA9IGk4\n" - "a19nZXRfdGVtcF90eXBlKGluZGV4KTsKLQlpZiAodHlwZSA8IDApCi0JCXJldHVybiB0eXBlOwot\n" - "CWlmICh0eXBlID49IEFSUkFZX1NJWkUobGFiZWxzKSkKLQkJdHlwZSA9IEFSUkFZX1NJWkUobGFi\n" - "ZWxzKSAtIDE7Ci0JcmV0dXJuIHNwcmludGYoYnVmLCAiJXNcbiIsIGxhYmVsc1t0eXBlXSk7Ci19\n" - "Ci0KLXN0YXRpYyBzc2l6ZV90IGk4a19od21vbl9zaG93X3RlbXAoc3RydWN0IGRldmljZSAqZGV2\n" - "LAotCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZhdHRyLAotCQkJCSAgIGNoYXIg\n" - "KmJ1ZikKLXsKLQlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4\n" - "OwotCWludCB0ZW1wOwotCi0JdGVtcCA9IGk4a19nZXRfdGVtcChpbmRleCk7Ci0JaWYgKHRlbXAg\n" - "PCAwKQotCQlyZXR1cm4gdGVtcDsKLQlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwgdGVtcCAq\n" - "IDEwMDApOwotfQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19mYW5fbGFiZWwoc3Ry\n" - "dWN0IGRldmljZSAqZGV2LAotCQkJCQlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwK\n" - "LQkJCQkJY2hhciAqYnVmKQotewotCXN0YXRpYyBjb25zdCBjaGFyICogY29uc3QgbGFiZWxzW10g\n" - "PSB7Ci0JCSJQcm9jZXNzb3IgRmFuIiwKLQkJIk1vdGhlcmJvYXJkIEZhbiIsCi0JCSJWaWRlbyBG\n" - "YW4iLAotCQkiUG93ZXIgU3VwcGx5IEZhbiIsCi0JCSJDaGlwc2V0IEZhbiIsCi0JCSJPdGhlciBG\n" - "YW4iLAotCX07Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRl\n" - "eDsKLQlib29sIGRvY2sgPSBmYWxzZTsKLQlpbnQgdHlwZTsKLQotCXR5cGUgPSBpOGtfZ2V0X2Zh\n" - "bl90eXBlKGluZGV4KTsKLQlpZiAodHlwZSA8IDApCi0JCXJldHVybiB0eXBlOwotCi0JaWYgKHR5\n" - "cGUgJiAweDEwKSB7Ci0JCWRvY2sgPSB0cnVlOwotCQl0eXBlICY9IDB4MEY7Ci0JfQotCi0JaWYg\n" - "KHR5cGUgPj0gQVJSQVlfU0laRShsYWJlbHMpKQotCQl0eXBlID0gKEFSUkFZX1NJWkUobGFiZWxz\n" - "KSAtIDEpOwotCi0JcmV0dXJuIHNwcmludGYoYnVmLCAiJXMlc1xuIiwgKGRvY2sgPyAiRG9ja2lu\n" - "ZyAiIDogIiIpLCBsYWJlbHNbdHlwZV0pOwotfQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25f\n" - "c2hvd19mYW4oc3RydWN0IGRldmljZSAqZGV2LAotCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1\n" - "dGUgKmRldmF0dHIsCi0JCQkJICBjaGFyICpidWYpCi17Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29y\n" - "X2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsKLQlpbnQgZmFuX3NwZWVkOwotCi0JZmFuX3NwZWVk\n" - "ID0gaThrX2dldF9mYW5fc3BlZWQoaW5kZXgpOwotCWlmIChmYW5fc3BlZWQgPCAwKQotCQlyZXR1\n" - "cm4gZmFuX3NwZWVkOwotCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCBmYW5fc3BlZWQpOwot\n" - "fQotCi1zdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19wd20oc3RydWN0IGRldmljZSAqZGV2\n" - "LAotCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCi0JCQkJICBjaGFyICpi\n" - "dWYpCi17Ci0JaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsK\n" - "LQlpbnQgc3RhdHVzOwotCi0Jc3RhdHVzID0gaThrX2dldF9mYW5fc3RhdHVzKGluZGV4KTsKLQlp\n" - "ZiAoc3RhdHVzIDwgMCkKLQkJcmV0dXJuIC1FSU87Ci0JcmV0dXJuIHNwcmludGYoYnVmLCAiJWRc\n" - "biIsIGNsYW1wX3ZhbChzdGF0dXMgKiBpOGtfcHdtX211bHQsIDAsIDI1NSkpOwotfQotCi1zdGF0\n" - "aWMgc3NpemVfdCBpOGtfaHdtb25fc2V0X3B3bShzdHJ1Y3QgZGV2aWNlICpkZXYsCi0JCQkJIHN0\n" - "cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLAotCQkJCSBjb25zdCBjaGFyICpidWYsIHNpemVf\n" - "dCBjb3VudCkKLXsKLQlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoYXR0ciktPmluZGV4\n" - "OwotCXVuc2lnbmVkIGxvbmcgdmFsOwotCWludCBlcnI7Ci0KLQllcnIgPSBrc3RydG91bChidWYs\n" - "IDEwLCAmdmFsKTsKLQlpZiAoZXJyKQotCQlyZXR1cm4gZXJyOwotCXZhbCA9IGNsYW1wX3ZhbChE\n" - "SVZfUk9VTkRfQ0xPU0VTVCh2YWwsIGk4a19wd21fbXVsdCksIDAsIGk4a19mYW5fbWF4KTsKLQot\n" - "CW11dGV4X2xvY2soJmk4a19tdXRleCk7Ci0JZXJyID0gaThrX3NldF9mYW4oaW5kZXgsIHZhbCk7\n" - "Ci0JbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOwotCi0JcmV0dXJuIGVyciA8IDAgPyAtRUlPIDog\n" - "Y291bnQ7Ci19Ci0KLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfaW5wdXQsIFNfSVJV\n" - "R08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDApOwotc3RhdGljIFNFTlNPUl9ERVZJQ0Vf\n" - "QVRUUih0ZW1wMV9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbCwgTlVM\n" - "TCwKLQkJCSAgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX2lucHV0LCBTX0lS\n" - "VUdPLCBpOGtfaHdtb25fc2hvd190ZW1wLCBOVUxMLCAxKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNF\n" - "X0FUVFIodGVtcDJfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXBfbGFiZWwsIE5V\n" - "TEwsCi0JCQkgIDEpOwotc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19pbnB1dCwgU19J\n" - "UlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcCwgTlVMTCwgMik7Ci1zdGF0aWMgU0VOU09SX0RFVklD\n" - "RV9BVFRSKHRlbXAzX2xhYmVsLCBTX0lSVUdPLCBpOGtfaHdtb25fc2hvd190ZW1wX2xhYmVsLCBO\n" - "VUxMLAotCQkJICAyKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDRfaW5wdXQsIFNf\n" - "SVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDMpOwotc3RhdGljIFNFTlNPUl9ERVZJ\n" - "Q0VfQVRUUih0ZW1wNF9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbCwg\n" - "TlVMTCwKLQkJCSAgMyk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKGZhbjFfaW5wdXQsIFNf\n" - "SVJVR08sIGk4a19od21vbl9zaG93X2ZhbiwgTlVMTCwgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklD\n" - "RV9BVFRSKGZhbjFfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9zaG93X2Zhbl9sYWJlbCwgTlVM\n" - "TCwKLQkJCSAgMCk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHB3bTEsIFNfSVJVR08gfCBT\n" - "X0lXVVNSLCBpOGtfaHdtb25fc2hvd19wd20sCi0JCQkgIGk4a19od21vbl9zZXRfcHdtLCAwKTsK\n" - "LXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFuMl9pbnB1dCwgU19JUlVHTywgaThrX2h3bW9u\n" - "X3Nob3dfZmFuLCBOVUxMLAotCQkJICAxKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFu\n" - "Ml9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuX2xhYmVsLCBOVUxMLAotCQkJICAx\n" - "KTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIocHdtMiwgU19JUlVHTyB8IFNfSVdVU1IsIGk4\n" - "a19od21vbl9zaG93X3B3bSwKLQkJCSAgaThrX2h3bW9uX3NldF9wd20sIDEpOwotCi1zdGF0aWMg\n" - "c3RydWN0IGF0dHJpYnV0ZSAqaThrX2F0dHJzW10gPSB7Ci0JJnNlbnNvcl9kZXZfYXR0cl90ZW1w\n" - "MV9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAwICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9s\n" - "YWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAxICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMl9pbnB1\n" - "dC5kZXZfYXR0ci5hdHRyLAkvKiAyICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMl9sYWJlbC5k\n" - "ZXZfYXR0ci5hdHRyLAkvKiAzICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wM19pbnB1dC5kZXZf\n" - "YXR0ci5hdHRyLAkvKiA0ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wM19sYWJlbC5kZXZfYXR0\n" - "ci5hdHRyLAkvKiA1ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9pbnB1dC5kZXZfYXR0ci5h\n" - "dHRyLAkvKiA2ICovCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9sYWJlbC5kZXZfYXR0ci5hdHRy\n" - "LAkvKiA3ICovCi0JJnNlbnNvcl9kZXZfYXR0cl9mYW4xX2lucHV0LmRldl9hdHRyLmF0dHIsCS8q\n" - "IDggKi8KLQkmc2Vuc29yX2Rldl9hdHRyX2ZhbjFfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyogOSAq\n" - "LwotCSZzZW5zb3JfZGV2X2F0dHJfcHdtMS5kZXZfYXR0ci5hdHRyLAkJLyogMTAgKi8KLQkmc2Vu\n" - "c29yX2Rldl9hdHRyX2ZhbjJfaW5wdXQuZGV2X2F0dHIuYXR0ciwJLyogMTEgKi8KLQkmc2Vuc29y\n" - "X2Rldl9hdHRyX2ZhbjJfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyogMTIgKi8KLQkmc2Vuc29yX2Rl\n" - "dl9hdHRyX3B3bTIuZGV2X2F0dHIuYXR0ciwJCS8qIDEzICovCi0JTlVMTAotfTsKLQotc3RhdGlj\n" - "IHVtb2RlX3QgaThrX2lzX3Zpc2libGUoc3RydWN0IGtvYmplY3QgKmtvYmosIHN0cnVjdCBhdHRy\n" - "aWJ1dGUgKmF0dHIsCi0JCQkgICAgICBpbnQgaW5kZXgpCi17Ci0JaWYgKGluZGV4ID49IDAgJiYg\n" - "aW5kZXggPD0gMSAmJgotCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RF\n" - "TVAxKSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDIgJiYgaW5kZXggPD0gMyAmJgotCSAg\n" - "ICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RFTVAyKSkKLQkJcmV0dXJuIDA7\n" - "Ci0JaWYgKGluZGV4ID49IDQgJiYgaW5kZXggPD0gNSAmJgotCSAgICAhKGk4a19od21vbl9mbGFn\n" - "cyAmIEk4S19IV01PTl9IQVZFX1RFTVAzKSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDYg\n" - "JiYgaW5kZXggPD0gNyAmJgotCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZF\n" - "X1RFTVA0KSkKLQkJcmV0dXJuIDA7Ci0JaWYgKGluZGV4ID49IDggJiYgaW5kZXggPD0gMTAgJiYK\n" - "LQkgICAgIShpOGtfaHdtb25fZmxhZ3MgJiBJOEtfSFdNT05fSEFWRV9GQU4xKSkKLQkJcmV0dXJu\n" - "IDA7Ci0JaWYgKGluZGV4ID49IDExICYmIGluZGV4IDw9IDEzICYmCi0JICAgICEoaThrX2h3bW9u\n" - "X2ZsYWdzICYgSThLX0hXTU9OX0hBVkVfRkFOMikpCi0JCXJldHVybiAwOwotCi0JcmV0dXJuIGF0\n" - "dHItPm1vZGU7Ci19Ci0KLXN0YXRpYyBjb25zdCBzdHJ1Y3QgYXR0cmlidXRlX2dyb3VwIGk4a19n\n" - "cm91cCA9IHsKLQkuYXR0cnMgPSBpOGtfYXR0cnMsCi0JLmlzX3Zpc2libGUgPSBpOGtfaXNfdmlz\n" - "aWJsZSwKLX07Ci1fX0FUVFJJQlVURV9HUk9VUFMoaThrKTsKLQotc3RhdGljIGludCBfX2luaXQg\n" - "aThrX2luaXRfaHdtb24odm9pZCkKLXsKLQlpbnQgZXJyOwotCi0JaThrX2h3bW9uX2ZsYWdzID0g\n" - "MDsKLQotCS8qIENQVSB0ZW1wZXJhdHVyZSBhdHRyaWJ1dGVzLCBpZiB0ZW1wZXJhdHVyZSB0eXBl\n" - "IGlzIE9LICovCi0JZXJyID0gaThrX2dldF90ZW1wX3R5cGUoMCk7Ci0JaWYgKGVyciA+PSAwKQot\n" - "CQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfVEVNUDE7Ci0JLyogY2hlY2sgZm9y\n" - "IGFkZGl0aW9uYWwgdGVtcGVyYXR1cmUgc2Vuc29ycyAqLwotCWVyciA9IGk4a19nZXRfdGVtcF90\n" - "eXBlKDEpOwotCWlmIChlcnIgPj0gMCkKLQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9I\n" - "QVZFX1RFTVAyOwotCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDIpOwotCWlmIChlcnIgPj0gMCkK\n" - "LQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVAzOwotCWVyciA9IGk4a19n\n" - "ZXRfdGVtcF90eXBlKDMpOwotCWlmIChlcnIgPj0gMCkKLQkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4\n" - "S19IV01PTl9IQVZFX1RFTVA0OwotCi0JLyogRmlyc3QgZmFuIGF0dHJpYnV0ZXMsIGlmIGZhbiB0\n" - "eXBlIGlzIE9LICovCi0JZXJyID0gaThrX2dldF9mYW5fdHlwZSgwKTsKLQlpZiAoZXJyID49IDAp\n" - "Ci0JCWk4a19od21vbl9mbGFncyB8PSBJOEtfSFdNT05fSEFWRV9GQU4xOwotCi0JLyogU2Vjb25k\n" - "IGZhbiBhdHRyaWJ1dGVzLCBpZiBmYW4gdHlwZSBpcyBPSyAqLwotCWVyciA9IGk4a19nZXRfZmFu\n" - "X3R5cGUoMSk7Ci0JaWYgKGVyciA+PSAwKQotCQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9O\n" - "X0hBVkVfRkFOMjsKLQotCWk4a19od21vbl9kZXYgPSBod21vbl9kZXZpY2VfcmVnaXN0ZXJfd2l0\n" - "aF9ncm91cHMoTlVMTCwgImk4ayIsIE5VTEwsCi0JCQkJCQkJICBpOGtfZ3JvdXBzKTsKLQlpZiAo\n" - "SVNfRVJSKGk4a19od21vbl9kZXYpKSB7Ci0JCWVyciA9IFBUUl9FUlIoaThrX2h3bW9uX2Rldik7\n" - "Ci0JCWk4a19od21vbl9kZXYgPSBOVUxMOwotCQlwcl9lcnIoImh3bW9uIHJlZ2lzdHJhdGlvbiBm\n" - "YWlsZWQgKCVkKVxuIiwgZXJyKTsKLQkJcmV0dXJuIGVycjsKLQl9Ci0JcmV0dXJuIDA7Ci19Ci0K\n" - "LXN0cnVjdCBpOGtfY29uZmlnX2RhdGEgewotCXVpbnQgZmFuX211bHQ7Ci0JdWludCBmYW5fbWF4\n" - "OwotfTsKLQotZW51bSBpOGtfY29uZmlncyB7Ci0JREVMTF9MQVRJVFVERV9ENTIwLAotCURFTExf\n" - "UFJFQ0lTSU9OXzQ5MCwKLQlERUxMX1NUVURJTywKLQlERUxMX1hQUywKLX07Ci0KLXN0YXRpYyBj\n" - "b25zdCBzdHJ1Y3QgaThrX2NvbmZpZ19kYXRhIGk4a19jb25maWdfZGF0YVtdID0gewotCVtERUxM\n" - "X0xBVElUVURFX0Q1MjBdID0gewotCQkuZmFuX211bHQgPSAxLAotCQkuZmFuX21heCA9IEk4S19G\n" - "QU5fVFVSQk8sCi0JfSwKLQlbREVMTF9QUkVDSVNJT05fNDkwXSA9IHsKLQkJLmZhbl9tdWx0ID0g\n" - "MSwKLQkJLmZhbl9tYXggPSBJOEtfRkFOX1RVUkJPLAotCX0sCi0JW0RFTExfU1RVRElPXSA9IHsK\n" - "LQkJLmZhbl9tdWx0ID0gMSwKLQkJLmZhbl9tYXggPSBJOEtfRkFOX0hJR0gsCi0JfSwKLQlbREVM\n" - "TF9YUFNdID0gewotCQkuZmFuX211bHQgPSAxLAotCQkuZmFuX21heCA9IEk4S19GQU5fSElHSCwK\n" - "LQl9LAotfTsKLQotc3RhdGljIHN0cnVjdCBkbWlfc3lzdGVtX2lkIGk4a19kbWlfdGFibGVbXSBf\n" - "X2luaXRkYXRhID0gewotCXsKLQkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24iLAotCQkubWF0Y2hl\n" - "cyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKLQkJ\n" - "CURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiSW5zcGlyb24iKSwKLQkJfSwKLQl9LAotCXsK\n" - "LQkJLmlkZW50ID0gIkRlbGwgTGF0aXR1ZGUiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRD\n" - "SChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKLQkJCURNSV9NQVRDSChETUlfUFJP\n" - "RFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKLQkJfSwKLQl9LAotCXsKLQkJLmlkZW50ID0gIkRlbGwg\n" - "SW5zcGlyb24gMiIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9S\n" - "LCAiRGVsbCBJbmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIkluc3Bpcm9u\n" - "IiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJEZWxsIExhdGl0dWRlIEQ1MjAiLAotCQku\n" - "bWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAot\n" - "CQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJMYXRpdHVkZSBENTIwIiksCi0JCX0sCi0J\n" - "CS5kcml2ZXJfZGF0YSA9ICh2b2lkICopJmk4a19jb25maWdfZGF0YVtERUxMX0xBVElUVURFX0Q1\n" - "MjBdLAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBMYXRpdHVkZSAyIiwKLQkJLm1hdGNoZXMg\n" - "PSB7Ci0JCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKLQkJCURNSV9N\n" - "QVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKLQkJfSwKLQl9LAotCXsJLyogVUsg\n" - "SW5zcGlyb24gNjQwMCAgKi8KLQkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24gMyIsCi0JCS5tYXRj\n" - "aGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCi0JCQlE\n" - "TUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1NMDYxIiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5p\n" - "ZGVudCA9ICJEZWxsIEluc3Bpcm9uIDMiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChE\n" - "TUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05B\n" - "TUUsICJNUDA2MSIpLAotCQl9LAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBQcmVjaXNpb24g\n" - "NDkwIiwKLQkJLm1hdGNoZXMgPSB7Ci0JCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxs\n" - "IEluYy4iKSwKLQkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLAotCQkJCSAgIlByZWNpc2lv\n" - "biBXb3JrU3RhdGlvbiA0OTAiKSwKLQkJfSwKLQkJLmRyaXZlcl9kYXRhID0gKHZvaWQgKikmaThr\n" - "X2NvbmZpZ19kYXRhW0RFTExfUFJFQ0lTSU9OXzQ5MF0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJE\n" - "ZWxsIFByZWNpc2lvbiIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVO\n" - "RE9SLCAiRGVsbCBJbmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlByZWNp\n" - "c2lvbiIpLAotCQl9LAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBWb3N0cm8iLAotCQkubWF0\n" - "Y2hlcyA9IHsKLQkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJ\n" - "RE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJWb3N0cm8iKSwKLQkJfSwKLQl9LAotCXsKLQkJ\n" - "LmlkZW50ID0gIkRlbGwgWFBTNDIxIiwKLQkJLm1hdGNoZXMgPSB7Ci0JCQlETUlfTUFUQ0goRE1J\n" - "X1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKLQkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1F\n" - "LCAiWFBTIEw0MjFYIiksCi0JCX0sCi0JfSwKLQl7Ci0JCS5pZGVudCA9ICJEZWxsIFN0dWRpbyIs\n" - "Ci0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMu\n" - "IiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlN0dWRpbyIpLAotCQl9LAotCQku\n" - "ZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9TVFVESU9dLAotCX0s\n" - "Ci0JewotCQkuaWRlbnQgPSAiRGVsbCBYUFMgMTMiLAotCQkubWF0Y2hlcyA9IHsKLQkJCURNSV9N\n" - "QVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAotCQkJRE1JX01BVENIKERNSV9QUk9E\n" - "VUNUX05BTUUsICJYUFMxMyIpLAotCQl9LAotCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtf\n" - "Y29uZmlnX2RhdGFbREVMTF9YUFNdLAotCX0sCi0JewotCQkuaWRlbnQgPSAiRGVsbCBYUFMgTTE0\n" - "MCIsCi0JCS5tYXRjaGVzID0gewotCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJ\n" - "bmMuIiksCi0JCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1YQzA1MSIpLAotCQl9LAot\n" - "CQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9YUFNdLAotCX0s\n" - "Ci0JeyB9Ci19OwotCi1NT0RVTEVfREVWSUNFX1RBQkxFKGRtaSwgaThrX2RtaV90YWJsZSk7Ci0K\n" - "LS8qCi0gKiBQcm9iZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgc3VwcG9ydGVkIGxhcHRvcC4KLSAq\n" - "Lwotc3RhdGljIGludCBfX2luaXQgaThrX3Byb2JlKHZvaWQpCi17Ci0JY29uc3Qgc3RydWN0IGRt\n" - "aV9zeXN0ZW1faWQgKmlkOwotCWludCBmYW4sIHJldDsKLQotCS8qCi0JICogR2V0IERNSSBpbmZv\n" - "cm1hdGlvbgotCSAqLwotCWlmICghZG1pX2NoZWNrX3N5c3RlbShpOGtfZG1pX3RhYmxlKSkgewot\n" - "CQlpZiAoIWlnbm9yZV9kbWkgJiYgIWZvcmNlKQotCQkJcmV0dXJuIC1FTk9ERVY7Ci0KLQkJcHJf\n" - "aW5mbygibm90IHJ1bm5pbmcgb24gYSBzdXBwb3J0ZWQgRGVsbCBzeXN0ZW0uXG4iKTsKLQkJcHJf\n" - "aW5mbygidmVuZG9yPSVzLCBtb2RlbD0lcywgdmVyc2lvbj0lc1xuIiwKLQkJCWk4a19nZXRfZG1p\n" - "X2RhdGEoRE1JX1NZU19WRU5ET1IpLAotCQkJaThrX2dldF9kbWlfZGF0YShETUlfUFJPRFVDVF9O\n" - "QU1FKSwKLQkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX0JJT1NfVkVSU0lPTikpOwotCX0KLQotCXN0\n" - "cmxjcHkoYmlvc192ZXJzaW9uLCBpOGtfZ2V0X2RtaV9kYXRhKERNSV9CSU9TX1ZFUlNJT04pLAot\n" - "CQlzaXplb2YoYmlvc192ZXJzaW9uKSk7Ci0KLQkvKgotCSAqIEdldCBTTU0gRGVsbCBzaWduYXR1\n" - "cmUKLQkgKi8KLQlpZiAoaThrX2dldF9kZWxsX3NpZ25hdHVyZShJOEtfU01NX0dFVF9ERUxMX1NJ\n" - "RzEpICYmCi0JICAgIGk4a19nZXRfZGVsbF9zaWduYXR1cmUoSThLX1NNTV9HRVRfREVMTF9TSUcy\n" - "KSkgewotCQlwcl9lcnIoInVuYWJsZSB0byBnZXQgU01NIERlbGwgc2lnbmF0dXJlXG4iKTsKLQkJ\n" - "aWYgKCFmb3JjZSkKLQkJCXJldHVybiAtRU5PREVWOwotCX0KLQotCS8qCi0JICogU2V0IGZhbiBt\n" - "dWx0aXBsaWVyIGFuZCBtYXhpbWFsIGZhbiBzcGVlZCBmcm9tIGRtaSBjb25maWcKLQkgKiBWYWx1\n" - "ZXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbWV0ZXJzIG92ZXJyaWRlIHZhbHVlcyBmcm9tIGRt\n" - "aQotCSAqLwotCWlkID0gZG1pX2ZpcnN0X21hdGNoKGk4a19kbWlfdGFibGUpOwotCWlmIChpZCAm\n" - "JiBpZC0+ZHJpdmVyX2RhdGEpIHsKLQkJY29uc3Qgc3RydWN0IGk4a19jb25maWdfZGF0YSAqY29u\n" - "ZiA9IGlkLT5kcml2ZXJfZGF0YTsKLQkJaWYgKCFmYW5fbXVsdCAmJiBjb25mLT5mYW5fbXVsdCkK\n" - "LQkJCWZhbl9tdWx0ID0gY29uZi0+ZmFuX211bHQ7Ci0JCWlmICghZmFuX21heCAmJiBjb25mLT5m\n" - "YW5fbWF4KQotCQkJZmFuX21heCA9IGNvbmYtPmZhbl9tYXg7Ci0JfQotCi0JaThrX2Zhbl9tYXgg\n" - "PSBmYW5fbWF4ID8gOiBJOEtfRkFOX0hJR0g7CS8qIE11c3Qgbm90IGJlIDAgKi8KLQlpOGtfcHdt\n" - "X211bHQgPSBESVZfUk9VTkRfVVAoMjU1LCBpOGtfZmFuX21heCk7Ci0KLQlpZiAoIWZhbl9tdWx0\n" - "KSB7Ci0JCS8qCi0JCSAqIEF1dG9kZXRlY3QgZmFuIG11bHRpcGxpZXIgYmFzZWQgb24gbm9taW5h\n" - "bCBycG0KLQkJICogSWYgZmFuIHJlcG9ydHMgcnBtIHZhbHVlIHRvbyBoaWdoIHRoZW4gc2V0IG11\n" - "bHRpcGxpZXIgdG8gMQotCQkgKi8KLQkJZm9yIChmYW4gPSAwOyBmYW4gPCAyOyArK2Zhbikgewot\n" - "CQkJcmV0ID0gaThrX2dldF9mYW5fbm9taW5hbF9zcGVlZChmYW4sIGk4a19mYW5fbWF4KTsKLQkJ\n" - "CWlmIChyZXQgPCAwKQotCQkJCWNvbnRpbnVlOwotCQkJaWYgKHJldCA+IEk4S19GQU5fTUFYX1JQ\n" - "TSkKLQkJCQlpOGtfZmFuX211bHQgPSAxOwotCQkJYnJlYWs7Ci0JCX0KLQl9IGVsc2UgewotCQkv\n" - "KiBGYW4gbXVsdGlwbGllciB3YXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbSBvciBpbiBkbWkg\n" - "Ki8KLQkJaThrX2Zhbl9tdWx0ID0gZmFuX211bHQ7Ci0JfQotCi0JcmV0dXJuIDA7Ci19Ci0KLXN0\n" - "YXRpYyBpbnQgX19pbml0IGk4a19pbml0KHZvaWQpCi17Ci0Jc3RydWN0IHByb2NfZGlyX2VudHJ5\n" - "ICpwcm9jX2k4azsKLQlpbnQgZXJyOwotCi0JLyogQXJlIHdlIHJ1bm5pbmcgb24gYW4gc3VwcG9y\n" - "dGVkIGxhcHRvcD8gKi8KLQlpZiAoaThrX3Byb2JlKCkpCi0JCXJldHVybiAtRU5PREVWOwotCi0J\n" - "LyogUmVnaXN0ZXIgdGhlIHByb2MgZW50cnkgKi8KLQlwcm9jX2k4ayA9IHByb2NfY3JlYXRlKCJp\n" - "OGsiLCAwLCBOVUxMLCAmaThrX2ZvcHMpOwotCWlmICghcHJvY19pOGspCi0JCXJldHVybiAtRU5P\n" - "RU5UOwotCi0JZXJyID0gaThrX2luaXRfaHdtb24oKTsKLQlpZiAoZXJyKQotCQlnb3RvIGV4aXRf\n" - "cmVtb3ZlX3Byb2M7Ci0KLQlyZXR1cm4gMDsKLQotIGV4aXRfcmVtb3ZlX3Byb2M6Ci0JcmVtb3Zl\n" - "X3Byb2NfZW50cnkoImk4ayIsIE5VTEwpOwotCXJldHVybiBlcnI7Ci19Ci0KLXN0YXRpYyB2b2lk\n" - "IF9fZXhpdCBpOGtfZXhpdCh2b2lkKQotewotCWh3bW9uX2RldmljZV91bnJlZ2lzdGVyKGk4a19o\n" - "d21vbl9kZXYpOwotCXJlbW92ZV9wcm9jX2VudHJ5KCJpOGsiLCBOVUxMKTsKLX0KLQotbW9kdWxl\n" - "X2luaXQoaThrX2luaXQpOwotbW9kdWxlX2V4aXQoaThrX2V4aXQpOwpkaWZmIC0tZ2l0IGEvZHJp\n" - "dmVycy9od21vbi9NYWtlZmlsZSBiL2RyaXZlcnMvaHdtb24vTWFrZWZpbGUKaW5kZXggNmM5NDE0\n" - "Ny4uMWMzZTQ1OCAxMDA2NDQKLS0tIGEvZHJpdmVycy9od21vbi9NYWtlZmlsZQorKysgYi9kcml2\n" - "ZXJzL2h3bW9uL01ha2VmaWxlCkBAIC0xNTUsNiArMTU1LDcgQEAgb2JqLSQoQ09ORklHX1NFTlNP\n" - "UlNfVzgzTDc4NVRTKQkrPSB3ODNsNzg1dHMubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfVzgzTDc4\n" - "Nk5HKQkrPSB3ODNsNzg2bmcubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfV004MzFYKQkrPSB3bTgz\n" - "MXgtaHdtb24ubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfV004MzUwKQkrPSB3bTgzNTAtaHdtb24u\n" - "bworb2JqLSQoQ09ORklHX0k4SykJCSs9IGRlbGwtc21tLWh3bW9uLm8KIAogb2JqLSQoQ09ORklH\n" - "X1BNQlVTKQkJKz0gcG1idXMvCiAKZGlmZiAtLWdpdCBhL2RyaXZlcnMvaHdtb24vZGVsbC1zbW0t\n" - "aHdtb24uYyBiL2RyaXZlcnMvaHdtb24vZGVsbC1zbW0taHdtb24uYwpuZXcgZmlsZSBtb2RlIDEw\n" - "MDY0NAppbmRleCAwMDAwMDAwLi4yYjA0ZTRmCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9o\n" - "d21vbi9kZWxsLXNtbS1od21vbi5jCkBAIC0wLDAgKzEsMTAwNyBAQAorLyoKKyAqIGRlbGwtc21t\n" - "LWh3bW9uLmMgLS0gTGludXggZHJpdmVyIGZvciBhY2Nlc3NpbmcgdGhlIFNNTSBCSU9TIG9uIERl\n" - "bGwgbGFwdG9wcy4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMDEgIE1hc3NpbW8gRGFsIFpvdHRv\n" - "IDxkekBkZWJpYW4ub3JnPgorICoKKyAqIEh3bW9uIGludGVncmF0aW9uOgorICogQ29weXJpZ2h0\n" - "IChDKSAyMDExICBKZWFuIERlbHZhcmUgPGpkZWx2YXJlQHN1c2UuZGU+CisgKiBDb3B5cmlnaHQg\n" - "KEMpIDIwMTMsIDIwMTQgIEd1ZW50ZXIgUm9lY2sgPGxpbnV4QHJvZWNrLXVzLm5ldD4KKyAqIENv\n" - "cHlyaWdodCAoQykgMjAxNCwgMjAxNSAgUGFsaSBSb2jDoXIgPHBhbGkucm9oYXJAZ21haWwuY29t\n" - "PgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJp\n" - "YnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgKiB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBH\n" - "ZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUKKyAqIEZyZWUgU29mdHdh\n" - "cmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMiwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkK\n" - "KyAqIGxhdGVyIHZlcnNpb24uCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGlu\n" - "IHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dAorICogV0lUSE9VVCBBTlkgV0FS\n" - "UkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICogTUVSQ0hBTlRB\n" - "QklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUK\n" - "KyAqIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAqLworCisjZGVm\n" - "aW5lIHByX2ZtdChmbXQpIEtCVUlMRF9NT0ROQU1FICI6ICIgZm10CisKKyNpbmNsdWRlIDxsaW51\n" - "eC9kZWxheS5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1ZGUgPGxpbnV4L3R5\n" - "cGVzLmg+CisjaW5jbHVkZSA8bGludXgvaW5pdC5oPgorI2luY2x1ZGUgPGxpbnV4L3Byb2NfZnMu\n" - "aD4KKyNpbmNsdWRlIDxsaW51eC9zZXFfZmlsZS5oPgorI2luY2x1ZGUgPGxpbnV4L2RtaS5oPgor\n" - "I2luY2x1ZGUgPGxpbnV4L2NhcGFiaWxpdHkuaD4KKyNpbmNsdWRlIDxsaW51eC9tdXRleC5oPgor\n" - "I2luY2x1ZGUgPGxpbnV4L2h3bW9uLmg+CisjaW5jbHVkZSA8bGludXgvaHdtb24tc3lzZnMuaD4K\n" - "KyNpbmNsdWRlIDxsaW51eC91YWNjZXNzLmg+CisjaW5jbHVkZSA8bGludXgvaW8uaD4KKyNpbmNs\n" - "dWRlIDxsaW51eC9zY2hlZC5oPgorCisjaW5jbHVkZSA8bGludXgvaThrLmg+CisKKyNkZWZpbmUg\n" - "SThLX1NNTV9GTl9TVEFUVVMJMHgwMDI1CisjZGVmaW5lIEk4S19TTU1fUE9XRVJfU1RBVFVTCTB4\n" - "MDA2OQorI2RlZmluZSBJOEtfU01NX1NFVF9GQU4JCTB4MDFhMworI2RlZmluZSBJOEtfU01NX0dF\n" - "VF9GQU4JCTB4MDBhMworI2RlZmluZSBJOEtfU01NX0dFVF9TUEVFRAkweDAyYTMKKyNkZWZpbmUg\n" - "SThLX1NNTV9HRVRfRkFOX1RZUEUJMHgwM2EzCisjZGVmaW5lIEk4S19TTU1fR0VUX05PTV9TUEVF\n" - "RAkweDA0YTMKKyNkZWZpbmUgSThLX1NNTV9HRVRfVEVNUAkweDEwYTMKKyNkZWZpbmUgSThLX1NN\n" - "TV9HRVRfVEVNUF9UWVBFCTB4MTFhMworI2RlZmluZSBJOEtfU01NX0dFVF9ERUxMX1NJRzEJMHhm\n" - "ZWEzCisjZGVmaW5lIEk4S19TTU1fR0VUX0RFTExfU0lHMgkweGZmYTMKKworI2RlZmluZSBJOEtf\n" - "RkFOX01VTFQJCTMwCisjZGVmaW5lIEk4S19GQU5fTUFYX1JQTQkJMzAwMDAKKyNkZWZpbmUgSThL\n" - "X01BWF9URU1QCQkxMjcKKworI2RlZmluZSBJOEtfRk5fTk9ORQkJMHgwMAorI2RlZmluZSBJOEtf\n" - "Rk5fVVAJCTB4MDEKKyNkZWZpbmUgSThLX0ZOX0RPV04JCTB4MDIKKyNkZWZpbmUgSThLX0ZOX01V\n" - "VEUJCTB4MDQKKyNkZWZpbmUgSThLX0ZOX01BU0sJCTB4MDcKKyNkZWZpbmUgSThLX0ZOX1NISUZU\n" - "CQk4CisKKyNkZWZpbmUgSThLX1BPV0VSX0FDCQkweDA1CisjZGVmaW5lIEk4S19QT1dFUl9CQVRU\n" - "RVJZCTB4MDEKKworc3RhdGljIERFRklORV9NVVRFWChpOGtfbXV0ZXgpOworc3RhdGljIGNoYXIg\n" - "Ymlvc192ZXJzaW9uWzRdOworc3RhdGljIHN0cnVjdCBkZXZpY2UgKmk4a19od21vbl9kZXY7Citz\n" - "dGF0aWMgdTMyIGk4a19od21vbl9mbGFnczsKK3N0YXRpYyB1aW50IGk4a19mYW5fbXVsdCA9IEk4\n" - "S19GQU5fTVVMVDsKK3N0YXRpYyB1aW50IGk4a19wd21fbXVsdDsKK3N0YXRpYyB1aW50IGk4a19m\n" - "YW5fbWF4ID0gSThLX0ZBTl9ISUdIOworCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVAxCSgx\n" - "IDw8IDApCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVAyCSgxIDw8IDEpCisjZGVmaW5lIEk4\n" - "S19IV01PTl9IQVZFX1RFTVAzCSgxIDw8IDIpCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX1RFTVA0\n" - "CSgxIDw8IDMpCisjZGVmaW5lIEk4S19IV01PTl9IQVZFX0ZBTjEJKDEgPDwgNCkKKyNkZWZpbmUg\n" - "SThLX0hXTU9OX0hBVkVfRkFOMgkoMSA8PCA1KQorCitNT0RVTEVfQVVUSE9SKCJNYXNzaW1vIERh\n" - "bCBab3R0byAoZHpAZGViaWFuLm9yZykiKTsKK01PRFVMRV9BVVRIT1IoIlBhbGkgUm9ow6FyIDxw\n" - "YWxpLnJvaGFyQGdtYWlsLmNvbT4iKTsKK01PRFVMRV9ERVNDUklQVElPTigiRHJpdmVyIGZvciBh\n" - "Y2Nlc3NpbmcgU01NIEJJT1Mgb24gRGVsbCBsYXB0b3BzIik7CitNT0RVTEVfTElDRU5TRSgiR1BM\n" - "Iik7CitNT0RVTEVfQUxJQVMoImk4ayIpOworCitzdGF0aWMgYm9vbCBmb3JjZTsKK21vZHVsZV9w\n" - "YXJhbShmb3JjZSwgYm9vbCwgMCk7CitNT0RVTEVfUEFSTV9ERVNDKGZvcmNlLCAiRm9yY2UgbG9h\n" - "ZGluZyB3aXRob3V0IGNoZWNraW5nIGZvciBzdXBwb3J0ZWQgbW9kZWxzIik7CisKK3N0YXRpYyBi\n" - "b29sIGlnbm9yZV9kbWk7Cittb2R1bGVfcGFyYW0oaWdub3JlX2RtaSwgYm9vbCwgMCk7CitNT0RV\n" - "TEVfUEFSTV9ERVNDKGlnbm9yZV9kbWksICJDb250aW51ZSBwcm9iaW5nIGhhcmR3YXJlIGV2ZW4g\n" - "aWYgRE1JIGRhdGEgZG9lcyBub3QgbWF0Y2giKTsKKworc3RhdGljIGJvb2wgcmVzdHJpY3RlZDsK\n" - "K21vZHVsZV9wYXJhbShyZXN0cmljdGVkLCBib29sLCAwKTsKK01PRFVMRV9QQVJNX0RFU0MocmVz\n" - "dHJpY3RlZCwgIkFsbG93IGZhbiBjb250cm9sIGlmIFNZU19BRE1JTiBjYXBhYmlsaXR5IHNldCIp\n" - "OworCitzdGF0aWMgYm9vbCBwb3dlcl9zdGF0dXM7Cittb2R1bGVfcGFyYW0ocG93ZXJfc3RhdHVz\n" - "LCBib29sLCAwNjAwKTsKK01PRFVMRV9QQVJNX0RFU0MocG93ZXJfc3RhdHVzLCAiUmVwb3J0IHBv\n" - "d2VyIHN0YXR1cyBpbiAvcHJvYy9pOGsiKTsKKworc3RhdGljIHVpbnQgZmFuX211bHQ7Cittb2R1\n" - "bGVfcGFyYW0oZmFuX211bHQsIHVpbnQsIDApOworTU9EVUxFX1BBUk1fREVTQyhmYW5fbXVsdCwg\n" - "IkZhY3RvciB0byBtdWx0aXBseSBmYW4gc3BlZWQgd2l0aCAoZGVmYXVsdDogYXV0b2RldGVjdCki\n" - "KTsKKworc3RhdGljIHVpbnQgZmFuX21heDsKK21vZHVsZV9wYXJhbShmYW5fbWF4LCB1aW50LCAw\n" - "KTsKK01PRFVMRV9QQVJNX0RFU0MoZmFuX21heCwgIk1heGltdW0gY29uZmlndXJhYmxlIGZhbiBz\n" - "cGVlZCAoZGVmYXVsdDogYXV0b2RldGVjdCkiKTsKKworc3RhdGljIGludCBpOGtfb3Blbl9mcyhz\n" - "dHJ1Y3QgaW5vZGUgKmlub2RlLCBzdHJ1Y3QgZmlsZSAqZmlsZSk7CitzdGF0aWMgbG9uZyBpOGtf\n" - "aW9jdGwoc3RydWN0IGZpbGUgKiwgdW5zaWduZWQgaW50LCB1bnNpZ25lZCBsb25nKTsKKworc3Rh\n" - "dGljIGNvbnN0IHN0cnVjdCBmaWxlX29wZXJhdGlvbnMgaThrX2ZvcHMgPSB7CisJLm93bmVyCQk9\n" - "IFRISVNfTU9EVUxFLAorCS5vcGVuCQk9IGk4a19vcGVuX2ZzLAorCS5yZWFkCQk9IHNlcV9yZWFk\n" - "LAorCS5sbHNlZWsJCT0gc2VxX2xzZWVrLAorCS5yZWxlYXNlCT0gc2luZ2xlX3JlbGVhc2UsCisJ\n" - "LnVubG9ja2VkX2lvY3RsCT0gaThrX2lvY3RsLAorfTsKKworc3RydWN0IHNtbV9yZWdzIHsKKwl1\n" - "bnNpZ25lZCBpbnQgZWF4OworCXVuc2lnbmVkIGludCBlYnggX19wYWNrZWQ7CisJdW5zaWduZWQg\n" - "aW50IGVjeCBfX3BhY2tlZDsKKwl1bnNpZ25lZCBpbnQgZWR4IF9fcGFja2VkOworCXVuc2lnbmVk\n" - "IGludCBlc2kgX19wYWNrZWQ7CisJdW5zaWduZWQgaW50IGVkaSBfX3BhY2tlZDsKK307CisKK3N0\n" - "YXRpYyBpbmxpbmUgY29uc3QgY2hhciAqaThrX2dldF9kbWlfZGF0YShpbnQgZmllbGQpCit7CisJ\n" - "Y29uc3QgY2hhciAqZG1pX2RhdGEgPSBkbWlfZ2V0X3N5c3RlbV9pbmZvKGZpZWxkKTsKKworCXJl\n" - "dHVybiBkbWlfZGF0YSAmJiAqZG1pX2RhdGEgPyBkbWlfZGF0YSA6ICI/IjsKK30KKworLyoKKyAq\n" - "IENhbGwgdGhlIFN5c3RlbSBNYW5hZ2VtZW50IE1vZGUgQklPUy4gQ29kZSBwcm92aWRlZCBieSBK\n" - "b25hdGhhbiBCdXp6YXJkLgorICovCitzdGF0aWMgaW50IGk4a19zbW0oc3RydWN0IHNtbV9yZWdz\n" - "ICpyZWdzKQoreworCWludCByYzsKKwlpbnQgZWF4ID0gcmVncy0+ZWF4OworCWNwdW1hc2tfdmFy\n" - "X3Qgb2xkX21hc2s7CisKKwkvKiBTTU0gcmVxdWlyZXMgQ1BVIDAgKi8KKwlpZiAoIWFsbG9jX2Nw\n" - "dW1hc2tfdmFyKCZvbGRfbWFzaywgR0ZQX0tFUk5FTCkpCisJCXJldHVybiAtRU5PTUVNOworCWNw\n" - "dW1hc2tfY29weShvbGRfbWFzaywgJmN1cnJlbnQtPmNwdXNfYWxsb3dlZCk7CisJcmMgPSBzZXRf\n" - "Y3B1c19hbGxvd2VkX3B0cihjdXJyZW50LCBjcHVtYXNrX29mKDApKTsKKwlpZiAocmMpCisJCWdv\n" - "dG8gb3V0OworCWlmIChzbXBfcHJvY2Vzc29yX2lkKCkgIT0gMCkgeworCQlyYyA9IC1FQlVTWTsK\n" - "KwkJZ290byBvdXQ7CisJfQorCisjaWYgZGVmaW5lZChDT05GSUdfWDg2XzY0KQorCWFzbSB2b2xh\n" - "dGlsZSgicHVzaHEgJSVyYXhcblx0IgorCQkibW92bCAwKCUlcmF4KSwlJWVkeFxuXHQiCisJCSJw\n" - "dXNocSAlJXJkeFxuXHQiCisJCSJtb3ZsIDQoJSVyYXgpLCUlZWJ4XG5cdCIKKwkJIm1vdmwgOCgl\n" - "JXJheCksJSVlY3hcblx0IgorCQkibW92bCAxMiglJXJheCksJSVlZHhcblx0IgorCQkibW92bCAx\n" - "NiglJXJheCksJSVlc2lcblx0IgorCQkibW92bCAyMCglJXJheCksJSVlZGlcblx0IgorCQkicG9w\n" - "cSAlJXJheFxuXHQiCisJCSJvdXQgJSVhbCwkMHhiMlxuXHQiCisJCSJvdXQgJSVhbCwkMHg4NFxu\n" - "XHQiCisJCSJ4Y2hncSAlJXJheCwoJSVyc3ApXG5cdCIKKwkJIm1vdmwgJSVlYngsNCglJXJheClc\n" - "blx0IgorCQkibW92bCAlJWVjeCw4KCUlcmF4KVxuXHQiCisJCSJtb3ZsICUlZWR4LDEyKCUlcmF4\n" - "KVxuXHQiCisJCSJtb3ZsICUlZXNpLDE2KCUlcmF4KVxuXHQiCisJCSJtb3ZsICUlZWRpLDIwKCUl\n" - "cmF4KVxuXHQiCisJCSJwb3BxICUlcmR4XG5cdCIKKwkJIm1vdmwgJSVlZHgsMCglJXJheClcblx0\n" - "IgorCQkicHVzaGZxXG5cdCIKKwkJInBvcHEgJSVyYXhcblx0IgorCQkiYW5kbCAkMSwlJWVheFxu\n" - "IgorCQk6ICI9YSIocmMpCisJCTogICAgImEiKHJlZ3MpCisJCTogICAgIiVlYngiLCAiJWVjeCIs\n" - "ICIlZWR4IiwgIiVlc2kiLCAiJWVkaSIsICJtZW1vcnkiKTsKKyNlbHNlCisJYXNtIHZvbGF0aWxl\n" - "KCJwdXNobCAlJWVheFxuXHQiCisJICAgICJtb3ZsIDAoJSVlYXgpLCUlZWR4XG5cdCIKKwkgICAg\n" - "InB1c2ggJSVlZHhcblx0IgorCSAgICAibW92bCA0KCUlZWF4KSwlJWVieFxuXHQiCisJICAgICJt\n" - "b3ZsIDgoJSVlYXgpLCUlZWN4XG5cdCIKKwkgICAgIm1vdmwgMTIoJSVlYXgpLCUlZWR4XG5cdCIK\n" - "KwkgICAgIm1vdmwgMTYoJSVlYXgpLCUlZXNpXG5cdCIKKwkgICAgIm1vdmwgMjAoJSVlYXgpLCUl\n" - "ZWRpXG5cdCIKKwkgICAgInBvcGwgJSVlYXhcblx0IgorCSAgICAib3V0ICUlYWwsJDB4YjJcblx0\n" - "IgorCSAgICAib3V0ICUlYWwsJDB4ODRcblx0IgorCSAgICAieGNoZ2wgJSVlYXgsKCUlZXNwKVxu\n" - "XHQiCisJICAgICJtb3ZsICUlZWJ4LDQoJSVlYXgpXG5cdCIKKwkgICAgIm1vdmwgJSVlY3gsOCgl\n" - "JWVheClcblx0IgorCSAgICAibW92bCAlJWVkeCwxMiglJWVheClcblx0IgorCSAgICAibW92bCAl\n" - "JWVzaSwxNiglJWVheClcblx0IgorCSAgICAibW92bCAlJWVkaSwyMCglJWVheClcblx0IgorCSAg\n" - "ICAicG9wbCAlJWVkeFxuXHQiCisJICAgICJtb3ZsICUlZWR4LDAoJSVlYXgpXG5cdCIKKwkgICAg\n" - "ImxhaGZcblx0IgorCSAgICAic2hybCAkOCwlJWVheFxuXHQiCisJICAgICJhbmRsICQxLCUlZWF4\n" - "XG4iCisJICAgIDogIj1hIihyYykKKwkgICAgOiAgICAiYSIocmVncykKKwkgICAgOiAgICAiJWVi\n" - "eCIsICIlZWN4IiwgIiVlZHgiLCAiJWVzaSIsICIlZWRpIiwgIm1lbW9yeSIpOworI2VuZGlmCisJ\n" - "aWYgKHJjICE9IDAgfHwgKHJlZ3MtPmVheCAmIDB4ZmZmZikgPT0gMHhmZmZmIHx8IHJlZ3MtPmVh\n" - "eCA9PSBlYXgpCisJCXJjID0gLUVJTlZBTDsKKworb3V0OgorCXNldF9jcHVzX2FsbG93ZWRfcHRy\n" - "KGN1cnJlbnQsIG9sZF9tYXNrKTsKKwlmcmVlX2NwdW1hc2tfdmFyKG9sZF9tYXNrKTsKKwlyZXR1\n" - "cm4gcmM7Cit9CisKKy8qCisgKiBSZWFkIHRoZSBGbiBrZXkgc3RhdHVzLgorICovCitzdGF0aWMg\n" - "aW50IGk4a19nZXRfZm5fc3RhdHVzKHZvaWQpCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7\n" - "IC5lYXggPSBJOEtfU01NX0ZOX1NUQVRVUywgfTsKKwlpbnQgcmM7CisKKwlyYyA9IGk4a19zbW0o\n" - "JnJlZ3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKworCXN3aXRjaCAoKHJlZ3MuZWF4\n" - "ID4+IEk4S19GTl9TSElGVCkgJiBJOEtfRk5fTUFTSykgeworCWNhc2UgSThLX0ZOX1VQOgorCQly\n" - "ZXR1cm4gSThLX1ZPTF9VUDsKKwljYXNlIEk4S19GTl9ET1dOOgorCQlyZXR1cm4gSThLX1ZPTF9E\n" - "T1dOOworCWNhc2UgSThLX0ZOX01VVEU6CisJCXJldHVybiBJOEtfVk9MX01VVEU7CisJZGVmYXVs\n" - "dDoKKwkJcmV0dXJuIDA7CisJfQorfQorCisvKgorICogUmVhZCB0aGUgcG93ZXIgc3RhdHVzLgor\n" - "ICovCitzdGF0aWMgaW50IGk4a19nZXRfcG93ZXJfc3RhdHVzKHZvaWQpCit7CisJc3RydWN0IHNt\n" - "bV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX1BPV0VSX1NUQVRVUywgfTsKKwlpbnQgcmM7\n" - "CisKKwlyYyA9IGk4a19zbW0oJnJlZ3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKwor\n" - "CXJldHVybiAocmVncy5lYXggJiAweGZmKSA9PSBJOEtfUE9XRVJfQUMgPyBJOEtfQUMgOiBJOEtf\n" - "QkFUVEVSWTsKK30KKworLyoKKyAqIFJlYWQgdGhlIGZhbiBzdGF0dXMuCisgKi8KK3N0YXRpYyBp\n" - "bnQgaThrX2dldF9mYW5fc3RhdHVzKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3Mg\n" - "PSB7IC5lYXggPSBJOEtfU01NX0dFVF9GQU4sIH07CisKKwlyZWdzLmVieCA9IGZhbiAmIDB4ZmY7\n" - "CisJcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiByZWdzLmVheCAmIDB4ZmY7Cit9CisKKy8qCisg\n" - "KiBSZWFkIHRoZSBmYW4gc3BlZWQgaW4gUlBNLgorICovCitzdGF0aWMgaW50IGk4a19nZXRfZmFu\n" - "X3NwZWVkKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtf\n" - "U01NX0dFVF9TUEVFRCwgfTsKKworCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKKwlyZXR1cm4gaThr\n" - "X3NtbSgmcmVncykgPyA6IChyZWdzLmVheCAmIDB4ZmZmZikgKiBpOGtfZmFuX211bHQ7Cit9CisK\n" - "Ky8qCisgKiBSZWFkIHRoZSBmYW4gdHlwZS4KKyAqLworc3RhdGljIGludCBpOGtfZ2V0X2Zhbl90\n" - "eXBlKGludCBmYW4pCit7CisJc3RydWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01N\n" - "X0dFVF9GQU5fVFlQRSwgfTsKKworCXJlZ3MuZWJ4ID0gZmFuICYgMHhmZjsKKwlyZXR1cm4gaThr\n" - "X3NtbSgmcmVncykgPyA6IHJlZ3MuZWF4ICYgMHhmZjsKK30KKworLyoKKyAqIFJlYWQgdGhlIGZh\n" - "biBub21pbmFsIHJwbSBmb3Igc3BlY2lmaWMgZmFuIHNwZWVkLgorICovCitzdGF0aWMgaW50IGk4\n" - "a19nZXRfZmFuX25vbWluYWxfc3BlZWQoaW50IGZhbiwgaW50IHNwZWVkKQoreworCXN0cnVjdCBz\n" - "bW1fcmVncyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9HRVRfTk9NX1NQRUVELCB9OworCisJcmVn\n" - "cy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwgOCk7CisJcmV0dXJuIGk4a19zbW0oJnJl\n" - "Z3MpID8gOiAocmVncy5lYXggJiAweGZmZmYpICogaThrX2Zhbl9tdWx0OworfQorCisvKgorICog\n" - "U2V0IHRoZSBmYW4gc3BlZWQgKG9mZiwgbG93LCBoaWdoKS4gUmV0dXJucyB0aGUgbmV3IGZhbiBz\n" - "dGF0dXMuCisgKi8KK3N0YXRpYyBpbnQgaThrX3NldF9mYW4oaW50IGZhbiwgaW50IHNwZWVkKQor\n" - "eworCXN0cnVjdCBzbW1fcmVncyByZWdzID0geyAuZWF4ID0gSThLX1NNTV9TRVRfRkFOLCB9Owor\n" - "CisJc3BlZWQgPSAoc3BlZWQgPCAwKSA/IDAgOiAoKHNwZWVkID4gaThrX2Zhbl9tYXgpID8gaThr\n" - "X2Zhbl9tYXggOiBzcGVlZCk7CisJcmVncy5lYnggPSAoZmFuICYgMHhmZikgfCAoc3BlZWQgPDwg\n" - "OCk7CisKKwlyZXR1cm4gaThrX3NtbSgmcmVncykgPyA6IGk4a19nZXRfZmFuX3N0YXR1cyhmYW4p\n" - "OworfQorCitzdGF0aWMgaW50IGk4a19nZXRfdGVtcF90eXBlKGludCBzZW5zb3IpCit7CisJc3Ry\n" - "dWN0IHNtbV9yZWdzIHJlZ3MgPSB7IC5lYXggPSBJOEtfU01NX0dFVF9URU1QX1RZUEUsIH07CisK\n" - "KwlyZWdzLmVieCA9IHNlbnNvciAmIDB4ZmY7CisJcmV0dXJuIGk4a19zbW0oJnJlZ3MpID8gOiBy\n" - "ZWdzLmVheCAmIDB4ZmY7Cit9CisKKy8qCisgKiBSZWFkIHRoZSBjcHUgdGVtcGVyYXR1cmUuCisg\n" - "Ki8KK3N0YXRpYyBpbnQgX2k4a19nZXRfdGVtcChpbnQgc2Vuc29yKQoreworCXN0cnVjdCBzbW1f\n" - "cmVncyByZWdzID0geworCQkuZWF4ID0gSThLX1NNTV9HRVRfVEVNUCwKKwkJLmVieCA9IHNlbnNv\n" - "ciAmIDB4ZmYsCisJfTsKKworCXJldHVybiBpOGtfc21tKCZyZWdzKSA/IDogcmVncy5lYXggJiAw\n" - "eGZmOworfQorCitzdGF0aWMgaW50IGk4a19nZXRfdGVtcChpbnQgc2Vuc29yKQoreworCWludCB0\n" - "ZW1wID0gX2k4a19nZXRfdGVtcChzZW5zb3IpOworCisJLyoKKwkgKiBTb21ldGltZXMgdGhlIHRl\n" - "bXBlcmF0dXJlIHNlbnNvciByZXR1cm5zIDB4OTksIHdoaWNoIGlzIG91dCBvZiByYW5nZS4KKwkg\n" - "KiBJbiB0aGlzIGNhc2Ugd2UgcmV0cnkgKG9uY2UpIGJlZm9yZSByZXR1cm5pbmcgYW4gZXJyb3Iu\n" - "CisJICMgMTAwMzY1NTEzNyAwMDAwMDA1OCAwMDAwNWE0YgorCSAjIDEwMDM2NTUxMzggMDAwMDAw\n" - "OTkgMDAwMDNhODAgPC0tLSAweDk5ID0gMTUzIGRlZ3JlZXMKKwkgIyAxMDAzNjU1MTM5IDAwMDAw\n" - "MDU0IDAwMDA1YzUyCisJICovCisJaWYgKHRlbXAgPT0gMHg5OSkgeworCQltc2xlZXAoMTAwKTsK\n" - "KwkJdGVtcCA9IF9pOGtfZ2V0X3RlbXAoc2Vuc29yKTsKKwl9CisJLyoKKwkgKiBSZXR1cm4gLUVO\n" - "T0RBVEEgZm9yIGFsbCBpbnZhbGlkIHRlbXBlcmF0dXJlcy4KKwkgKgorCSAqIEtub3duIGluc3Rh\n" - "bmNlcyBhcmUgdGhlIDB4OTkgdmFsdWUgYXMgc2VlbiBhYm92ZSBhcyB3ZWxsIGFzCisJICogMHhj\n" - "MSAoMTkzKSwgd2hpY2ggbWF5IGJlIHJldHVybmVkIHdoZW4gdHJ5aW5nIHRvIHJlYWQgdGhlIEdQ\n" - "VQorCSAqIHRlbXBlcmF0dXJlIGlmIHRoZSBzeXN0ZW0gc3VwcG9ydHMgYSBHUFUgYW5kIGl0IGlz\n" - "IGN1cnJlbnRseQorCSAqIHR1cm5lZCBvZmYuCisJICovCisJaWYgKHRlbXAgPiBJOEtfTUFYX1RF\n" - "TVApCisJCXJldHVybiAtRU5PREFUQTsKKworCXJldHVybiB0ZW1wOworfQorCitzdGF0aWMgaW50\n" - "IGk4a19nZXRfZGVsbF9zaWduYXR1cmUoaW50IHJlcV9mbikKK3sKKwlzdHJ1Y3Qgc21tX3JlZ3Mg\n" - "cmVncyA9IHsgLmVheCA9IHJlcV9mbiwgfTsKKwlpbnQgcmM7CisKKwlyYyA9IGk4a19zbW0oJnJl\n" - "Z3MpOworCWlmIChyYyA8IDApCisJCXJldHVybiByYzsKKworCXJldHVybiByZWdzLmVheCA9PSAx\n" - "MTQ1NjUxNTI3ICYmIHJlZ3MuZWR4ID09IDExNDUzOTIyMDQgPyAwIDogLTE7Cit9CisKK3N0YXRp\n" - "YyBpbnQKK2k4a19pb2N0bF91bmxvY2tlZChzdHJ1Y3QgZmlsZSAqZnAsIHVuc2lnbmVkIGludCBj\n" - "bWQsIHVuc2lnbmVkIGxvbmcgYXJnKQoreworCWludCB2YWwgPSAwOworCWludCBzcGVlZDsKKwl1\n" - "bnNpZ25lZCBjaGFyIGJ1ZmZbMTZdOworCWludCBfX3VzZXIgKmFyZ3AgPSAoaW50IF9fdXNlciAq\n" - "KWFyZzsKKworCWlmICghYXJncCkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlzd2l0Y2ggKGNtZCkg\n" - "eworCWNhc2UgSThLX0JJT1NfVkVSU0lPTjoKKwkJdmFsID0gKGJpb3NfdmVyc2lvblswXSA8PCAx\n" - "NikgfAorCQkJCShiaW9zX3ZlcnNpb25bMV0gPDwgOCkgfCBiaW9zX3ZlcnNpb25bMl07CisJCWJy\n" - "ZWFrOworCisJY2FzZSBJOEtfTUFDSElORV9JRDoKKwkJbWVtc2V0KGJ1ZmYsIDAsIDE2KTsKKwkJ\n" - "c3RybGNweShidWZmLCBpOGtfZ2V0X2RtaV9kYXRhKERNSV9QUk9EVUNUX1NFUklBTCksCisJCQlz\n" - "aXplb2YoYnVmZikpOworCQlicmVhazsKKworCWNhc2UgSThLX0ZOX1NUQVRVUzoKKwkJdmFsID0g\n" - "aThrX2dldF9mbl9zdGF0dXMoKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4S19QT1dFUl9TVEFUVVM6\n" - "CisJCXZhbCA9IGk4a19nZXRfcG93ZXJfc3RhdHVzKCk7CisJCWJyZWFrOworCisJY2FzZSBJOEtf\n" - "R0VUX1RFTVA6CisJCXZhbCA9IGk4a19nZXRfdGVtcCgwKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4\n" - "S19HRVRfU1BFRUQ6CisJCWlmIChjb3B5X2Zyb21fdXNlcigmdmFsLCBhcmdwLCBzaXplb2YoaW50\n" - "KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBpOGtfZ2V0X2Zhbl9zcGVlZCh2YWwp\n" - "OworCQlicmVhazsKKworCWNhc2UgSThLX0dFVF9GQU46CisJCWlmIChjb3B5X2Zyb21fdXNlcigm\n" - "dmFsLCBhcmdwLCBzaXplb2YoaW50KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBp\n" - "OGtfZ2V0X2Zhbl9zdGF0dXModmFsKTsKKwkJYnJlYWs7CisKKwljYXNlIEk4S19TRVRfRkFOOgor\n" - "CQlpZiAocmVzdHJpY3RlZCAmJiAhY2FwYWJsZShDQVBfU1lTX0FETUlOKSkKKwkJCXJldHVybiAt\n" - "RVBFUk07CisKKwkJaWYgKGNvcHlfZnJvbV91c2VyKCZ2YWwsIGFyZ3AsIHNpemVvZihpbnQpKSkK\n" - "KwkJCXJldHVybiAtRUZBVUxUOworCisJCWlmIChjb3B5X2Zyb21fdXNlcigmc3BlZWQsIGFyZ3Ag\n" - "KyAxLCBzaXplb2YoaW50KSkpCisJCQlyZXR1cm4gLUVGQVVMVDsKKworCQl2YWwgPSBpOGtfc2V0\n" - "X2Zhbih2YWwsIHNwZWVkKTsKKwkJYnJlYWs7CisKKwlkZWZhdWx0OgorCQlyZXR1cm4gLUVJTlZB\n" - "TDsKKwl9CisKKwlpZiAodmFsIDwgMCkKKwkJcmV0dXJuIHZhbDsKKworCXN3aXRjaCAoY21kKSB7\n" - "CisJY2FzZSBJOEtfQklPU19WRVJTSU9OOgorCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWws\n" - "IDQpKQorCQkJcmV0dXJuIC1FRkFVTFQ7CisKKwkJYnJlYWs7CisJY2FzZSBJOEtfTUFDSElORV9J\n" - "RDoKKwkJaWYgKGNvcHlfdG9fdXNlcihhcmdwLCBidWZmLCAxNikpCisJCQlyZXR1cm4gLUVGQVVM\n" - "VDsKKworCQlicmVhazsKKwlkZWZhdWx0OgorCQlpZiAoY29weV90b191c2VyKGFyZ3AsICZ2YWws\n" - "IHNpemVvZihpbnQpKSkKKwkJCXJldHVybiAtRUZBVUxUOworCisJCWJyZWFrOworCX0KKworCXJl\n" - "dHVybiAwOworfQorCitzdGF0aWMgbG9uZyBpOGtfaW9jdGwoc3RydWN0IGZpbGUgKmZwLCB1bnNp\n" - "Z25lZCBpbnQgY21kLCB1bnNpZ25lZCBsb25nIGFyZykKK3sKKwlsb25nIHJldDsKKworCW11dGV4\n" - "X2xvY2soJmk4a19tdXRleCk7CisJcmV0ID0gaThrX2lvY3RsX3VubG9ja2VkKGZwLCBjbWQsIGFy\n" - "Zyk7CisJbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOworCisJcmV0dXJuIHJldDsKK30KKworLyoK\n" - "KyAqIFByaW50IHRoZSBpbmZvcm1hdGlvbiBmb3IgL3Byb2MvaThrLgorICovCitzdGF0aWMgaW50\n" - "IGk4a19wcm9jX3Nob3coc3RydWN0IHNlcV9maWxlICpzZXEsIHZvaWQgKm9mZnNldCkKK3sKKwlp\n" - "bnQgZm5fa2V5LCBjcHVfdGVtcCwgYWNfcG93ZXI7CisJaW50IGxlZnRfZmFuLCByaWdodF9mYW4s\n" - "IGxlZnRfc3BlZWQsIHJpZ2h0X3NwZWVkOworCisJY3B1X3RlbXAJPSBpOGtfZ2V0X3RlbXAoMCk7\n" - "CQkJLyogMTExMDAgwrVzICovCisJbGVmdF9mYW4JPSBpOGtfZ2V0X2Zhbl9zdGF0dXMoSThLX0ZB\n" - "Tl9MRUZUKTsJLyogICA1ODAgwrVzICovCisJcmlnaHRfZmFuCT0gaThrX2dldF9mYW5fc3RhdHVz\n" - "KEk4S19GQU5fUklHSFQpOwkvKiAgIDU4MCDCtXMgKi8KKwlsZWZ0X3NwZWVkCT0gaThrX2dldF9m\n" - "YW5fc3BlZWQoSThLX0ZBTl9MRUZUKTsJLyogICA1ODAgwrVzICovCisJcmlnaHRfc3BlZWQJPSBp\n" - "OGtfZ2V0X2Zhbl9zcGVlZChJOEtfRkFOX1JJR0hUKTsJLyogICA1ODAgwrVzICovCisJZm5fa2V5\n" - "CQk9IGk4a19nZXRfZm5fc3RhdHVzKCk7CQkJLyogICA3NTAgwrVzICovCisJaWYgKHBvd2VyX3N0\n" - "YXR1cykKKwkJYWNfcG93ZXIgPSBpOGtfZ2V0X3Bvd2VyX3N0YXR1cygpOwkJLyogMTQ3MDAgwrVz\n" - "ICovCisJZWxzZQorCQlhY19wb3dlciA9IC0xOworCisJLyoKKwkgKiBJbmZvOgorCSAqCisJICog\n" - "MSkgIEZvcm1hdCB2ZXJzaW9uICh0aGlzIHdpbGwgY2hhbmdlIGlmIGZvcm1hdCBjaGFuZ2VzKQor\n" - "CSAqIDIpICBCSU9TIHZlcnNpb24KKwkgKiAzKSAgQklPUyBtYWNoaW5lIElECisJICogNCkgIENw\n" - "dSB0ZW1wZXJhdHVyZQorCSAqIDUpICBMZWZ0IGZhbiBzdGF0dXMKKwkgKiA2KSAgUmlnaHQgZmFu\n" - "IHN0YXR1cworCSAqIDcpICBMZWZ0IGZhbiBzcGVlZAorCSAqIDgpICBSaWdodCBmYW4gc3BlZWQK\n" - "KwkgKiA5KSAgQUMgcG93ZXIKKwkgKiAxMCkgRm4gS2V5IHN0YXR1cworCSAqLworCXJldHVybiBz\n" - "ZXFfcHJpbnRmKHNlcSwgIiVzICVzICVzICVkICVkICVkICVkICVkICVkICVkXG4iLAorCQkJICBJ\n" - "OEtfUFJPQ19GTVQsCisJCQkgIGJpb3NfdmVyc2lvbiwKKwkJCSAgaThrX2dldF9kbWlfZGF0YShE\n" - "TUlfUFJPRFVDVF9TRVJJQUwpLAorCQkJICBjcHVfdGVtcCwKKwkJCSAgbGVmdF9mYW4sIHJpZ2h0\n" - "X2ZhbiwgbGVmdF9zcGVlZCwgcmlnaHRfc3BlZWQsCisJCQkgIGFjX3Bvd2VyLCBmbl9rZXkpOwor\n" - "fQorCitzdGF0aWMgaW50IGk4a19vcGVuX2ZzKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBm\n" - "aWxlICpmaWxlKQoreworCXJldHVybiBzaW5nbGVfb3BlbihmaWxlLCBpOGtfcHJvY19zaG93LCBO\n" - "VUxMKTsKK30KKworCisvKgorICogSHdtb24gaW50ZXJmYWNlCisgKi8KKworc3RhdGljIHNzaXpl\n" - "X3QgaThrX2h3bW9uX3Nob3dfdGVtcF9sYWJlbChzdHJ1Y3QgZGV2aWNlICpkZXYsCisJCQkJCSBz\n" - "dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwKKwkJCQkJIGNoYXIgKmJ1ZikKK3sKKwlz\n" - "dGF0aWMgY29uc3QgY2hhciAqIGNvbnN0IGxhYmVsc1tdID0geworCQkiQ1BVIiwKKwkJIkdQVSIs\n" - "CisJCSJTT0RJTU0iLAorCQkiT3RoZXIiLAorCQkiQW1iaWVudCIsCisJCSJPdGhlciIsCisJfTsK\n" - "KwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0dHIoZGV2YXR0ciktPmluZGV4OworCWludCB0\n" - "eXBlOworCisJdHlwZSA9IGk4a19nZXRfdGVtcF90eXBlKGluZGV4KTsKKwlpZiAodHlwZSA8IDAp\n" - "CisJCXJldHVybiB0eXBlOworCWlmICh0eXBlID49IEFSUkFZX1NJWkUobGFiZWxzKSkKKwkJdHlw\n" - "ZSA9IEFSUkFZX1NJWkUobGFiZWxzKSAtIDE7CisJcmV0dXJuIHNwcmludGYoYnVmLCAiJXNcbiIs\n" - "IGxhYmVsc1t0eXBlXSk7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGk4a19od21vbl9zaG93X3RlbXAo\n" - "c3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZh\n" - "dHRyLAorCQkJCSAgIGNoYXIgKmJ1ZikKK3sKKwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2X2F0\n" - "dHIoZGV2YXR0ciktPmluZGV4OworCWludCB0ZW1wOworCisJdGVtcCA9IGk4a19nZXRfdGVtcChp\n" - "bmRleCk7CisJaWYgKHRlbXAgPCAwKQorCQlyZXR1cm4gdGVtcDsKKwlyZXR1cm4gc3ByaW50Zihi\n" - "dWYsICIlZFxuIiwgdGVtcCAqIDEwMDApOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25f\n" - "c2hvd19mYW5fbGFiZWwoc3RydWN0IGRldmljZSAqZGV2LAorCQkJCQlzdHJ1Y3QgZGV2aWNlX2F0\n" - "dHJpYnV0ZSAqZGV2YXR0ciwKKwkJCQkJY2hhciAqYnVmKQoreworCXN0YXRpYyBjb25zdCBjaGFy\n" - "ICogY29uc3QgbGFiZWxzW10gPSB7CisJCSJQcm9jZXNzb3IgRmFuIiwKKwkJIk1vdGhlcmJvYXJk\n" - "IEZhbiIsCisJCSJWaWRlbyBGYW4iLAorCQkiUG93ZXIgU3VwcGx5IEZhbiIsCisJCSJDaGlwc2V0\n" - "IEZhbiIsCisJCSJPdGhlciBGYW4iLAorCX07CisJaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9h\n" - "dHRyKGRldmF0dHIpLT5pbmRleDsKKwlib29sIGRvY2sgPSBmYWxzZTsKKwlpbnQgdHlwZTsKKwor\n" - "CXR5cGUgPSBpOGtfZ2V0X2Zhbl90eXBlKGluZGV4KTsKKwlpZiAodHlwZSA8IDApCisJCXJldHVy\n" - "biB0eXBlOworCisJaWYgKHR5cGUgJiAweDEwKSB7CisJCWRvY2sgPSB0cnVlOworCQl0eXBlICY9\n" - "IDB4MEY7CisJfQorCisJaWYgKHR5cGUgPj0gQVJSQVlfU0laRShsYWJlbHMpKQorCQl0eXBlID0g\n" - "KEFSUkFZX1NJWkUobGFiZWxzKSAtIDEpOworCisJcmV0dXJuIHNwcmludGYoYnVmLCAiJXMlc1xu\n" - "IiwgKGRvY2sgPyAiRG9ja2luZyAiIDogIiIpLCBsYWJlbHNbdHlwZV0pOworfQorCitzdGF0aWMg\n" - "c3NpemVfdCBpOGtfaHdtb25fc2hvd19mYW4oc3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgc3Ry\n" - "dWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCisJCQkJICBjaGFyICpidWYpCit7CisJaW50\n" - "IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpLT5pbmRleDsKKwlpbnQgZmFuX3Nw\n" - "ZWVkOworCisJZmFuX3NwZWVkID0gaThrX2dldF9mYW5fc3BlZWQoaW5kZXgpOworCWlmIChmYW5f\n" - "c3BlZWQgPCAwKQorCQlyZXR1cm4gZmFuX3NwZWVkOworCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVk\n" - "XG4iLCBmYW5fc3BlZWQpOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2hvd19wd20o\n" - "c3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0\n" - "dHIsCisJCQkJICBjaGFyICpidWYpCit7CisJaW50IGluZGV4ID0gdG9fc2Vuc29yX2Rldl9hdHRy\n" - "KGRldmF0dHIpLT5pbmRleDsKKwlpbnQgc3RhdHVzOworCisJc3RhdHVzID0gaThrX2dldF9mYW5f\n" - "c3RhdHVzKGluZGV4KTsKKwlpZiAoc3RhdHVzIDwgMCkKKwkJcmV0dXJuIC1FSU87CisJcmV0dXJu\n" - "IHNwcmludGYoYnVmLCAiJWRcbiIsIGNsYW1wX3ZhbChzdGF0dXMgKiBpOGtfcHdtX211bHQsIDAs\n" - "IDI1NSkpOworfQorCitzdGF0aWMgc3NpemVfdCBpOGtfaHdtb25fc2V0X3B3bShzdHJ1Y3QgZGV2\n" - "aWNlICpkZXYsCisJCQkJIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLAorCQkJCSBjb25z\n" - "dCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKK3sKKwlpbnQgaW5kZXggPSB0b19zZW5zb3JfZGV2\n" - "X2F0dHIoYXR0ciktPmluZGV4OworCXVuc2lnbmVkIGxvbmcgdmFsOworCWludCBlcnI7CisKKwll\n" - "cnIgPSBrc3RydG91bChidWYsIDEwLCAmdmFsKTsKKwlpZiAoZXJyKQorCQlyZXR1cm4gZXJyOwor\n" - "CXZhbCA9IGNsYW1wX3ZhbChESVZfUk9VTkRfQ0xPU0VTVCh2YWwsIGk4a19wd21fbXVsdCksIDAs\n" - "IGk4a19mYW5fbWF4KTsKKworCW11dGV4X2xvY2soJmk4a19tdXRleCk7CisJZXJyID0gaThrX3Nl\n" - "dF9mYW4oaW5kZXgsIHZhbCk7CisJbXV0ZXhfdW5sb2NrKCZpOGtfbXV0ZXgpOworCisJcmV0dXJu\n" - "IGVyciA8IDAgPyAtRUlPIDogY291bnQ7Cit9CisKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIo\n" - "dGVtcDFfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDApOworc3Rh\n" - "dGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3No\n" - "b3dfdGVtcF9sYWJlbCwgTlVMTCwKKwkJCSAgMCk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS\n" - "KHRlbXAyX2lucHV0LCBTX0lSVUdPLCBpOGtfaHdtb25fc2hvd190ZW1wLCBOVUxMLCAxKTsKK3N0\n" - "YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9z\n" - "aG93X3RlbXBfbGFiZWwsIE5VTEwsCisJCQkgIDEpOworc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRU\n" - "Uih0ZW1wM19pbnB1dCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfdGVtcCwgTlVMTCwgMik7Citz\n" - "dGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX2xhYmVsLCBTX0lSVUdPLCBpOGtfaHdtb25f\n" - "c2hvd190ZW1wX2xhYmVsLCBOVUxMLAorCQkJICAyKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FU\n" - "VFIodGVtcDRfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X3RlbXAsIE5VTEwsIDMpOwor\n" - "c3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wNF9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9u\n" - "X3Nob3dfdGVtcF9sYWJlbCwgTlVMTCwKKwkJCSAgMyk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9B\n" - "VFRSKGZhbjFfaW5wdXQsIFNfSVJVR08sIGk4a19od21vbl9zaG93X2ZhbiwgTlVMTCwgMCk7Citz\n" - "dGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKGZhbjFfbGFiZWwsIFNfSVJVR08sIGk4a19od21vbl9z\n" - "aG93X2Zhbl9sYWJlbCwgTlVMTCwKKwkJCSAgMCk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS\n" - "KHB3bTEsIFNfSVJVR08gfCBTX0lXVVNSLCBpOGtfaHdtb25fc2hvd19wd20sCisJCQkgIGk4a19o\n" - "d21vbl9zZXRfcHdtLCAwKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIoZmFuMl9pbnB1dCwg\n" - "U19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuLCBOVUxMLAorCQkJICAxKTsKK3N0YXRpYyBTRU5T\n" - "T1JfREVWSUNFX0FUVFIoZmFuMl9sYWJlbCwgU19JUlVHTywgaThrX2h3bW9uX3Nob3dfZmFuX2xh\n" - "YmVsLCBOVUxMLAorCQkJICAxKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIocHdtMiwgU19J\n" - "UlVHTyB8IFNfSVdVU1IsIGk4a19od21vbl9zaG93X3B3bSwKKwkJCSAgaThrX2h3bW9uX3NldF9w\n" - "d20sIDEpOworCitzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZSAqaThrX2F0dHJzW10gPSB7CisJJnNl\n" - "bnNvcl9kZXZfYXR0cl90ZW1wMV9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAwICovCisJJnNlbnNv\n" - "cl9kZXZfYXR0cl90ZW1wMV9sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAxICovCisJJnNlbnNvcl9k\n" - "ZXZfYXR0cl90ZW1wMl9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiAyICovCisJJnNlbnNvcl9kZXZf\n" - "YXR0cl90ZW1wMl9sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiAzICovCisJJnNlbnNvcl9kZXZfYXR0\n" - "cl90ZW1wM19pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiA0ICovCisJJnNlbnNvcl9kZXZfYXR0cl90\n" - "ZW1wM19sYWJlbC5kZXZfYXR0ci5hdHRyLAkvKiA1ICovCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1w\n" - "NF9pbnB1dC5kZXZfYXR0ci5hdHRyLAkvKiA2ICovCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1wNF9s\n" - "YWJlbC5kZXZfYXR0ci5hdHRyLAkvKiA3ICovCisJJnNlbnNvcl9kZXZfYXR0cl9mYW4xX2lucHV0\n" - "LmRldl9hdHRyLmF0dHIsCS8qIDggKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjFfbGFiZWwuZGV2\n" - "X2F0dHIuYXR0ciwJLyogOSAqLworCSZzZW5zb3JfZGV2X2F0dHJfcHdtMS5kZXZfYXR0ci5hdHRy\n" - "LAkJLyogMTAgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjJfaW5wdXQuZGV2X2F0dHIuYXR0ciwJ\n" - "LyogMTEgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX2ZhbjJfbGFiZWwuZGV2X2F0dHIuYXR0ciwJLyog\n" - "MTIgKi8KKwkmc2Vuc29yX2Rldl9hdHRyX3B3bTIuZGV2X2F0dHIuYXR0ciwJCS8qIDEzICovCisJ\n" - "TlVMTAorfTsKKworc3RhdGljIHVtb2RlX3QgaThrX2lzX3Zpc2libGUoc3RydWN0IGtvYmplY3Qg\n" - "KmtvYmosIHN0cnVjdCBhdHRyaWJ1dGUgKmF0dHIsCisJCQkgICAgICBpbnQgaW5kZXgpCit7CisJ\n" - "aWYgKGluZGV4ID49IDAgJiYgaW5kZXggPD0gMSAmJgorCSAgICAhKGk4a19od21vbl9mbGFncyAm\n" - "IEk4S19IV01PTl9IQVZFX1RFTVAxKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDIgJiYg\n" - "aW5kZXggPD0gMyAmJgorCSAgICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RF\n" - "TVAyKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDQgJiYgaW5kZXggPD0gNSAmJgorCSAg\n" - "ICAhKGk4a19od21vbl9mbGFncyAmIEk4S19IV01PTl9IQVZFX1RFTVAzKSkKKwkJcmV0dXJuIDA7\n" - "CisJaWYgKGluZGV4ID49IDYgJiYgaW5kZXggPD0gNyAmJgorCSAgICAhKGk4a19od21vbl9mbGFn\n" - "cyAmIEk4S19IV01PTl9IQVZFX1RFTVA0KSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDgg\n" - "JiYgaW5kZXggPD0gMTAgJiYKKwkgICAgIShpOGtfaHdtb25fZmxhZ3MgJiBJOEtfSFdNT05fSEFW\n" - "RV9GQU4xKSkKKwkJcmV0dXJuIDA7CisJaWYgKGluZGV4ID49IDExICYmIGluZGV4IDw9IDEzICYm\n" - "CisJICAgICEoaThrX2h3bW9uX2ZsYWdzICYgSThLX0hXTU9OX0hBVkVfRkFOMikpCisJCXJldHVy\n" - "biAwOworCisJcmV0dXJuIGF0dHItPm1vZGU7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgYXR0\n" - "cmlidXRlX2dyb3VwIGk4a19ncm91cCA9IHsKKwkuYXR0cnMgPSBpOGtfYXR0cnMsCisJLmlzX3Zp\n" - "c2libGUgPSBpOGtfaXNfdmlzaWJsZSwKK307CitfX0FUVFJJQlVURV9HUk9VUFMoaThrKTsKKwor\n" - "c3RhdGljIGludCBfX2luaXQgaThrX2luaXRfaHdtb24odm9pZCkKK3sKKwlpbnQgZXJyOworCisJ\n" - "aThrX2h3bW9uX2ZsYWdzID0gMDsKKworCS8qIENQVSB0ZW1wZXJhdHVyZSBhdHRyaWJ1dGVzLCBp\n" - "ZiB0ZW1wZXJhdHVyZSB0eXBlIGlzIE9LICovCisJZXJyID0gaThrX2dldF90ZW1wX3R5cGUoMCk7\n" - "CisJaWYgKGVyciA+PSAwKQorCQlpOGtfaHdtb25fZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfVEVN\n" - "UDE7CisJLyogY2hlY2sgZm9yIGFkZGl0aW9uYWwgdGVtcGVyYXR1cmUgc2Vuc29ycyAqLworCWVy\n" - "ciA9IGk4a19nZXRfdGVtcF90eXBlKDEpOworCWlmIChlcnIgPj0gMCkKKwkJaThrX2h3bW9uX2Zs\n" - "YWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVAyOworCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDIp\n" - "OworCWlmIChlcnIgPj0gMCkKKwkJaThrX2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RF\n" - "TVAzOworCWVyciA9IGk4a19nZXRfdGVtcF90eXBlKDMpOworCWlmIChlcnIgPj0gMCkKKwkJaThr\n" - "X2h3bW9uX2ZsYWdzIHw9IEk4S19IV01PTl9IQVZFX1RFTVA0OworCisJLyogRmlyc3QgZmFuIGF0\n" - "dHJpYnV0ZXMsIGlmIGZhbiB0eXBlIGlzIE9LICovCisJZXJyID0gaThrX2dldF9mYW5fdHlwZSgw\n" - "KTsKKwlpZiAoZXJyID49IDApCisJCWk4a19od21vbl9mbGFncyB8PSBJOEtfSFdNT05fSEFWRV9G\n" - "QU4xOworCisJLyogU2Vjb25kIGZhbiBhdHRyaWJ1dGVzLCBpZiBmYW4gdHlwZSBpcyBPSyAqLwor\n" - "CWVyciA9IGk4a19nZXRfZmFuX3R5cGUoMSk7CisJaWYgKGVyciA+PSAwKQorCQlpOGtfaHdtb25f\n" - "ZmxhZ3MgfD0gSThLX0hXTU9OX0hBVkVfRkFOMjsKKworCWk4a19od21vbl9kZXYgPSBod21vbl9k\n" - "ZXZpY2VfcmVnaXN0ZXJfd2l0aF9ncm91cHMoTlVMTCwgImk4ayIsIE5VTEwsCisJCQkJCQkJICBp\n" - "OGtfZ3JvdXBzKTsKKwlpZiAoSVNfRVJSKGk4a19od21vbl9kZXYpKSB7CisJCWVyciA9IFBUUl9F\n" - "UlIoaThrX2h3bW9uX2Rldik7CisJCWk4a19od21vbl9kZXYgPSBOVUxMOworCQlwcl9lcnIoImh3\n" - "bW9uIHJlZ2lzdHJhdGlvbiBmYWlsZWQgKCVkKVxuIiwgZXJyKTsKKwkJcmV0dXJuIGVycjsKKwl9\n" - "CisJcmV0dXJuIDA7Cit9CisKK3N0cnVjdCBpOGtfY29uZmlnX2RhdGEgeworCXVpbnQgZmFuX211\n" - "bHQ7CisJdWludCBmYW5fbWF4OworfTsKKworZW51bSBpOGtfY29uZmlncyB7CisJREVMTF9MQVRJ\n" - "VFVERV9ENTIwLAorCURFTExfUFJFQ0lTSU9OXzQ5MCwKKwlERUxMX1NUVURJTywKKwlERUxMX1hQ\n" - "UywKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaThrX2NvbmZpZ19kYXRhIGk4a19jb25maWdf\n" - "ZGF0YVtdID0geworCVtERUxMX0xBVElUVURFX0Q1MjBdID0geworCQkuZmFuX211bHQgPSAxLAor\n" - "CQkuZmFuX21heCA9IEk4S19GQU5fVFVSQk8sCisJfSwKKwlbREVMTF9QUkVDSVNJT05fNDkwXSA9\n" - "IHsKKwkJLmZhbl9tdWx0ID0gMSwKKwkJLmZhbl9tYXggPSBJOEtfRkFOX1RVUkJPLAorCX0sCisJ\n" - "W0RFTExfU1RVRElPXSA9IHsKKwkJLmZhbl9tdWx0ID0gMSwKKwkJLmZhbl9tYXggPSBJOEtfRkFO\n" - "X0hJR0gsCisJfSwKKwlbREVMTF9YUFNdID0geworCQkuZmFuX211bHQgPSAxLAorCQkuZmFuX21h\n" - "eCA9IEk4S19GQU5fSElHSCwKKwl9LAorfTsKKworc3RhdGljIHN0cnVjdCBkbWlfc3lzdGVtX2lk\n" - "IGk4a19kbWlfdGFibGVbXSBfX2luaXRkYXRhID0geworCXsKKwkJLmlkZW50ID0gIkRlbGwgSW5z\n" - "cGlyb24iLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRl\n" - "bGwgQ29tcHV0ZXIiKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiSW5zcGlyb24i\n" - "KSwKKwkJfSwKKwl9LAorCXsKKwkJLmlkZW50ID0gIkRlbGwgTGF0aXR1ZGUiLAorCQkubWF0Y2hl\n" - "cyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgQ29tcHV0ZXIiKSwKKwkJ\n" - "CURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKKwkJfSwKKwl9LAorCXsK\n" - "KwkJLmlkZW50ID0gIkRlbGwgSW5zcGlyb24gMiIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01B\n" - "VENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RV\n" - "Q1RfTkFNRSwgIkluc3Bpcm9uIiksCisJCX0sCisJfSwKKwl7CisJCS5pZGVudCA9ICJEZWxsIExh\n" - "dGl0dWRlIEQ1MjAiLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRP\n" - "UiwgIkRlbGwgSW5jLiIpLAorCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJMYXRpdHVk\n" - "ZSBENTIwIiksCisJCX0sCisJCS5kcml2ZXJfZGF0YSA9ICh2b2lkICopJmk4a19jb25maWdfZGF0\n" - "YVtERUxMX0xBVElUVURFX0Q1MjBdLAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVsbCBMYXRpdHVk\n" - "ZSAyIiwKKwkJLm1hdGNoZXMgPSB7CisJCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxs\n" - "IEluYy4iKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1FLCAiTGF0aXR1ZGUiKSwKKwkJ\n" - "fSwKKwl9LAorCXsJLyogVUsgSW5zcGlyb24gNjQwMCAgKi8KKwkJLmlkZW50ID0gIkRlbGwgSW5z\n" - "cGlyb24gMyIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9TWVNfVkVORE9SLCAi\n" - "RGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIk1NMDYxIiksCisJ\n" - "CX0sCisJfSwKKwl7CisJCS5pZGVudCA9ICJEZWxsIEluc3Bpcm9uIDMiLAorCQkubWF0Y2hlcyA9\n" - "IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAorCQkJRE1JX01B\n" - "VENIKERNSV9QUk9EVUNUX05BTUUsICJNUDA2MSIpLAorCQl9LAorCX0sCisJeworCQkuaWRlbnQg\n" - "PSAiRGVsbCBQcmVjaXNpb24gNDkwIiwKKwkJLm1hdGNoZXMgPSB7CisJCQlETUlfTUFUQ0goRE1J\n" - "X1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKKwkJCURNSV9NQVRDSChETUlfUFJPRFVDVF9OQU1F\n" - "LAorCQkJCSAgIlByZWNpc2lvbiBXb3JrU3RhdGlvbiA0OTAiKSwKKwkJfSwKKwkJLmRyaXZlcl9k\n" - "YXRhID0gKHZvaWQgKikmaThrX2NvbmZpZ19kYXRhW0RFTExfUFJFQ0lTSU9OXzQ5MF0sCisJfSwK\n" - "Kwl7CisJCS5pZGVudCA9ICJEZWxsIFByZWNpc2lvbiIsCisJCS5tYXRjaGVzID0geworCQkJRE1J\n" - "X01BVENIKERNSV9TWVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BS\n" - "T0RVQ1RfTkFNRSwgIlByZWNpc2lvbiIpLAorCQl9LAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVs\n" - "bCBWb3N0cm8iLAorCQkubWF0Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwg\n" - "IkRlbGwgSW5jLiIpLAorCQkJRE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJWb3N0cm8iKSwK\n" - "KwkJfSwKKwl9LAorCXsKKwkJLmlkZW50ID0gIkRlbGwgWFBTNDIxIiwKKwkJLm1hdGNoZXMgPSB7\n" - "CisJCQlETUlfTUFUQ0goRE1JX1NZU19WRU5ET1IsICJEZWxsIEluYy4iKSwKKwkJCURNSV9NQVRD\n" - "SChETUlfUFJPRFVDVF9OQU1FLCAiWFBTIEw0MjFYIiksCisJCX0sCisJfSwKKwl7CisJCS5pZGVu\n" - "dCA9ICJEZWxsIFN0dWRpbyIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9TWVNf\n" - "VkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwgIlN0\n" - "dWRpbyIpLAorCQl9LAorCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFb\n" - "REVMTF9TVFVESU9dLAorCX0sCisJeworCQkuaWRlbnQgPSAiRGVsbCBYUFMgMTMiLAorCQkubWF0\n" - "Y2hlcyA9IHsKKwkJCURNSV9NQVRDSChETUlfU1lTX1ZFTkRPUiwgIkRlbGwgSW5jLiIpLAorCQkJ\n" - "RE1JX01BVENIKERNSV9QUk9EVUNUX05BTUUsICJYUFMxMyIpLAorCQl9LAorCQkuZHJpdmVyX2Rh\n" - "dGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2RhdGFbREVMTF9YUFNdLAorCX0sCisJeworCQkuaWRl\n" - "bnQgPSAiRGVsbCBYUFMgTTE0MCIsCisJCS5tYXRjaGVzID0geworCQkJRE1JX01BVENIKERNSV9T\n" - "WVNfVkVORE9SLCAiRGVsbCBJbmMuIiksCisJCQlETUlfTUFUQ0goRE1JX1BST0RVQ1RfTkFNRSwg\n" - "Ik1YQzA1MSIpLAorCQl9LAorCQkuZHJpdmVyX2RhdGEgPSAodm9pZCAqKSZpOGtfY29uZmlnX2Rh\n" - "dGFbREVMTF9YUFNdLAorCX0sCisJeyB9Cit9OworCitNT0RVTEVfREVWSUNFX1RBQkxFKGRtaSwg\n" - "aThrX2RtaV90YWJsZSk7CisKKy8qCisgKiBQcm9iZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgc3Vw\n" - "cG9ydGVkIGxhcHRvcC4KKyAqLworc3RhdGljIGludCBfX2luaXQgaThrX3Byb2JlKHZvaWQpCit7\n" - "CisJY29uc3Qgc3RydWN0IGRtaV9zeXN0ZW1faWQgKmlkOworCWludCBmYW4sIHJldDsKKworCS8q\n" - "CisJICogR2V0IERNSSBpbmZvcm1hdGlvbgorCSAqLworCWlmICghZG1pX2NoZWNrX3N5c3RlbShp\n" - "OGtfZG1pX3RhYmxlKSkgeworCQlpZiAoIWlnbm9yZV9kbWkgJiYgIWZvcmNlKQorCQkJcmV0dXJu\n" - "IC1FTk9ERVY7CisKKwkJcHJfaW5mbygibm90IHJ1bm5pbmcgb24gYSBzdXBwb3J0ZWQgRGVsbCBz\n" - "eXN0ZW0uXG4iKTsKKwkJcHJfaW5mbygidmVuZG9yPSVzLCBtb2RlbD0lcywgdmVyc2lvbj0lc1xu\n" - "IiwKKwkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX1NZU19WRU5ET1IpLAorCQkJaThrX2dldF9kbWlf\n" - "ZGF0YShETUlfUFJPRFVDVF9OQU1FKSwKKwkJCWk4a19nZXRfZG1pX2RhdGEoRE1JX0JJT1NfVkVS\n" - "U0lPTikpOworCX0KKworCXN0cmxjcHkoYmlvc192ZXJzaW9uLCBpOGtfZ2V0X2RtaV9kYXRhKERN\n" - "SV9CSU9TX1ZFUlNJT04pLAorCQlzaXplb2YoYmlvc192ZXJzaW9uKSk7CisKKwkvKgorCSAqIEdl\n" - "dCBTTU0gRGVsbCBzaWduYXR1cmUKKwkgKi8KKwlpZiAoaThrX2dldF9kZWxsX3NpZ25hdHVyZShJ\n" - "OEtfU01NX0dFVF9ERUxMX1NJRzEpICYmCisJICAgIGk4a19nZXRfZGVsbF9zaWduYXR1cmUoSThL\n" - "X1NNTV9HRVRfREVMTF9TSUcyKSkgeworCQlwcl9lcnIoInVuYWJsZSB0byBnZXQgU01NIERlbGwg\n" - "c2lnbmF0dXJlXG4iKTsKKwkJaWYgKCFmb3JjZSkKKwkJCXJldHVybiAtRU5PREVWOworCX0KKwor\n" - "CS8qCisJICogU2V0IGZhbiBtdWx0aXBsaWVyIGFuZCBtYXhpbWFsIGZhbiBzcGVlZCBmcm9tIGRt\n" - "aSBjb25maWcKKwkgKiBWYWx1ZXMgc3BlY2lmaWVkIGluIG1vZHVsZSBwYXJhbWV0ZXJzIG92ZXJy\n" - "aWRlIHZhbHVlcyBmcm9tIGRtaQorCSAqLworCWlkID0gZG1pX2ZpcnN0X21hdGNoKGk4a19kbWlf\n" - "dGFibGUpOworCWlmIChpZCAmJiBpZC0+ZHJpdmVyX2RhdGEpIHsKKwkJY29uc3Qgc3RydWN0IGk4\n" - "a19jb25maWdfZGF0YSAqY29uZiA9IGlkLT5kcml2ZXJfZGF0YTsKKwkJaWYgKCFmYW5fbXVsdCAm\n" - "JiBjb25mLT5mYW5fbXVsdCkKKwkJCWZhbl9tdWx0ID0gY29uZi0+ZmFuX211bHQ7CisJCWlmICgh\n" - "ZmFuX21heCAmJiBjb25mLT5mYW5fbWF4KQorCQkJZmFuX21heCA9IGNvbmYtPmZhbl9tYXg7CisJ\n" - "fQorCisJaThrX2Zhbl9tYXggPSBmYW5fbWF4ID8gOiBJOEtfRkFOX0hJR0g7CS8qIE11c3Qgbm90\n" - "IGJlIDAgKi8KKwlpOGtfcHdtX211bHQgPSBESVZfUk9VTkRfVVAoMjU1LCBpOGtfZmFuX21heCk7\n" - "CisKKwlpZiAoIWZhbl9tdWx0KSB7CisJCS8qCisJCSAqIEF1dG9kZXRlY3QgZmFuIG11bHRpcGxp\n" - "ZXIgYmFzZWQgb24gbm9taW5hbCBycG0KKwkJICogSWYgZmFuIHJlcG9ydHMgcnBtIHZhbHVlIHRv\n" - "byBoaWdoIHRoZW4gc2V0IG11bHRpcGxpZXIgdG8gMQorCQkgKi8KKwkJZm9yIChmYW4gPSAwOyBm\n" - "YW4gPCAyOyArK2ZhbikgeworCQkJcmV0ID0gaThrX2dldF9mYW5fbm9taW5hbF9zcGVlZChmYW4s\n" - "IGk4a19mYW5fbWF4KTsKKwkJCWlmIChyZXQgPCAwKQorCQkJCWNvbnRpbnVlOworCQkJaWYgKHJl\n" - "dCA+IEk4S19GQU5fTUFYX1JQTSkKKwkJCQlpOGtfZmFuX211bHQgPSAxOworCQkJYnJlYWs7CisJ\n" - "CX0KKwl9IGVsc2UgeworCQkvKiBGYW4gbXVsdGlwbGllciB3YXMgc3BlY2lmaWVkIGluIG1vZHVs\n" - "ZSBwYXJhbSBvciBpbiBkbWkgKi8KKwkJaThrX2Zhbl9tdWx0ID0gZmFuX211bHQ7CisJfQorCisJ\n" - "cmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgX19pbml0IGk4a19pbml0KHZvaWQpCit7CisJc3Ry\n" - "dWN0IHByb2NfZGlyX2VudHJ5ICpwcm9jX2k4azsKKwlpbnQgZXJyOworCisJLyogQXJlIHdlIHJ1\n" - "bm5pbmcgb24gYW4gc3VwcG9ydGVkIGxhcHRvcD8gKi8KKwlpZiAoaThrX3Byb2JlKCkpCisJCXJl\n" - "dHVybiAtRU5PREVWOworCisJLyogUmVnaXN0ZXIgdGhlIHByb2MgZW50cnkgKi8KKwlwcm9jX2k4\n" - "ayA9IHByb2NfY3JlYXRlKCJpOGsiLCAwLCBOVUxMLCAmaThrX2ZvcHMpOworCWlmICghcHJvY19p\n" - "OGspCisJCXJldHVybiAtRU5PRU5UOworCisJZXJyID0gaThrX2luaXRfaHdtb24oKTsKKwlpZiAo\n" - "ZXJyKQorCQlnb3RvIGV4aXRfcmVtb3ZlX3Byb2M7CisKKwlyZXR1cm4gMDsKKworIGV4aXRfcmVt\n" - "b3ZlX3Byb2M6CisJcmVtb3ZlX3Byb2NfZW50cnkoImk4ayIsIE5VTEwpOworCXJldHVybiBlcnI7\n" - "Cit9CisKK3N0YXRpYyB2b2lkIF9fZXhpdCBpOGtfZXhpdCh2b2lkKQoreworCWh3bW9uX2Rldmlj\n" - "ZV91bnJlZ2lzdGVyKGk4a19od21vbl9kZXYpOworCXJlbW92ZV9wcm9jX2VudHJ5KCJpOGsiLCBO\n" - "VUxMKTsKK30KKworbW9kdWxlX2luaXQoaThrX2luaXQpOworbW9kdWxlX2V4aXQoaThrX2V4aXQp\n" - "OwotLSAKMS43LjkuNQoKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f\n" - "X19fX19fCmxtLXNlbnNvcnMgbWFpbGluZyBsaXN0CmxtLXNlbnNvcnNAbG0tc2Vuc29ycy5vcmcK\n" - aHR0cDovL2xpc3RzLmxtLXNlbnNvcnMub3JnL21haWxtYW4vbGlzdGluZm8vbG0tc2Vuc29ycw= + "This commit moves i8k driver to hwmon tree under name dell-smm-hwmon which is\n" + "better name then abbreviation i8k. For backward compatibility is added macro\n" + "MODULE_ALIAS(\"i8k\") so modprobe will load driver also old name i8k. CONFIG_I8K\n" + "compile option was not changed.\n" + "\n" + "This commit also adds me as maintainer of this new dell-smm-hwmon driver and\n" + "remove Guenter Roeck from list who is implicit maintainer all hwmon drivers.\n" + "\n" + "Signed-off-by: Pali Roh\303\241r <pali.rohar@gmail.com>\n" + "---\n" + " MAINTAINERS | 4 +-\n" + " drivers/char/Makefile | 1 -\n" + " drivers/char/i8k.c | 1005 ---------------------------------------\n" + " drivers/hwmon/Makefile | 1 +\n" + " drivers/hwmon/dell-smm-hwmon.c | 1007 ++++++++++++++++++++++++++++++++++++++++\n" + " 5 files changed, 1010 insertions(+), 1008 deletions(-)\n" + " delete mode 100644 drivers/char/i8k.c\n" + " create mode 100644 drivers/hwmon/dell-smm-hwmon.c\n" + "\n" + "diff --git a/MAINTAINERS b/MAINTAINERS\n" + "index 88c09ca..e54a07e 100644\n" + "--- a/MAINTAINERS\n" + "+++ b/MAINTAINERS\n" + "@@ -3063,9 +3063,9 @@ S:\tMaintained\n" + " F:\tdrivers/platform/x86/dell-laptop.c\n" + " \n" + " DELL LAPTOP SMM DRIVER\n" + "-M:\tGuenter Roeck <linux@roeck-us.net>\n" + "+M:\tPali Roh\303\241r <pali.rohar@gmail.com>\n" + " S:\tMaintained\n" + "-F:\tdrivers/char/i8k.c\n" + "+F:\tdrivers/hwmon/dell-smm-hwmon.c\n" + " F:\tinclude/uapi/linux/i8k.h\n" + " \n" + " DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)\n" + "diff --git a/drivers/char/Makefile b/drivers/char/Makefile\n" + "index d06cde26..1d9cf00 100644\n" + "--- a/drivers/char/Makefile\n" + "+++ b/drivers/char/Makefile\n" + "@@ -36,7 +36,6 @@ else\n" + " obj-$(CONFIG_NVRAM)\t+= nvram.o\n" + " endif\n" + " obj-$(CONFIG_TOSHIBA)\t\t+= toshiba.o\n" + "-obj-$(CONFIG_I8K)\t\t+= i8k.o\n" + " obj-$(CONFIG_DS1620)\t\t+= ds1620.o\n" + " obj-$(CONFIG_HW_RANDOM)\t\t+= hw_random/\n" + " obj-$(CONFIG_PPDEV)\t\t+= ppdev.o\n" + "diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c\n" + "deleted file mode 100644\n" + "index 24cc4ed..0000000\n" + "--- a/drivers/char/i8k.c\n" + "+++ /dev/null\n" + "@@ -1,1005 +0,0 @@\n" + "-/*\n" + "- * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops.\n" + "- *\n" + "- * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>\n" + "- *\n" + "- * Hwmon integration:\n" + "- * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>\n" + "- * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net>\n" + "- * Copyright (C) 2014 Pali Roh\303\241r <pali.rohar@gmail.com>\n" + "- *\n" + "- * This program is free software; you can redistribute it and/or modify it\n" + "- * under the terms of the GNU General Public License as published by the\n" + "- * Free Software Foundation; either version 2, or (at your option) any\n" + "- * later version.\n" + "- *\n" + "- * This program is distributed in the hope that it will be useful, but\n" + "- * WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + "- * General Public License for more details.\n" + "- */\n" + "-\n" + "-#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n" + "-\n" + "-#include <linux/delay.h>\n" + "-#include <linux/module.h>\n" + "-#include <linux/types.h>\n" + "-#include <linux/init.h>\n" + "-#include <linux/proc_fs.h>\n" + "-#include <linux/seq_file.h>\n" + "-#include <linux/dmi.h>\n" + "-#include <linux/capability.h>\n" + "-#include <linux/mutex.h>\n" + "-#include <linux/hwmon.h>\n" + "-#include <linux/hwmon-sysfs.h>\n" + "-#include <linux/uaccess.h>\n" + "-#include <linux/io.h>\n" + "-#include <linux/sched.h>\n" + "-\n" + "-#include <linux/i8k.h>\n" + "-\n" + "-#define I8K_SMM_FN_STATUS\t0x0025\n" + "-#define I8K_SMM_POWER_STATUS\t0x0069\n" + "-#define I8K_SMM_SET_FAN\t\t0x01a3\n" + "-#define I8K_SMM_GET_FAN\t\t0x00a3\n" + "-#define I8K_SMM_GET_SPEED\t0x02a3\n" + "-#define I8K_SMM_GET_FAN_TYPE\t0x03a3\n" + "-#define I8K_SMM_GET_NOM_SPEED\t0x04a3\n" + "-#define I8K_SMM_GET_TEMP\t0x10a3\n" + "-#define I8K_SMM_GET_TEMP_TYPE\t0x11a3\n" + "-#define I8K_SMM_GET_DELL_SIG1\t0xfea3\n" + "-#define I8K_SMM_GET_DELL_SIG2\t0xffa3\n" + "-\n" + "-#define I8K_FAN_MULT\t\t30\n" + "-#define I8K_FAN_MAX_RPM\t\t30000\n" + "-#define I8K_MAX_TEMP\t\t127\n" + "-\n" + "-#define I8K_FN_NONE\t\t0x00\n" + "-#define I8K_FN_UP\t\t0x01\n" + "-#define I8K_FN_DOWN\t\t0x02\n" + "-#define I8K_FN_MUTE\t\t0x04\n" + "-#define I8K_FN_MASK\t\t0x07\n" + "-#define I8K_FN_SHIFT\t\t8\n" + "-\n" + "-#define I8K_POWER_AC\t\t0x05\n" + "-#define I8K_POWER_BATTERY\t0x01\n" + "-\n" + "-static DEFINE_MUTEX(i8k_mutex);\n" + "-static char bios_version[4];\n" + "-static struct device *i8k_hwmon_dev;\n" + "-static u32 i8k_hwmon_flags;\n" + "-static uint i8k_fan_mult = I8K_FAN_MULT;\n" + "-static uint i8k_pwm_mult;\n" + "-static uint i8k_fan_max = I8K_FAN_HIGH;\n" + "-\n" + "-#define I8K_HWMON_HAVE_TEMP1\t(1 << 0)\n" + "-#define I8K_HWMON_HAVE_TEMP2\t(1 << 1)\n" + "-#define I8K_HWMON_HAVE_TEMP3\t(1 << 2)\n" + "-#define I8K_HWMON_HAVE_TEMP4\t(1 << 3)\n" + "-#define I8K_HWMON_HAVE_FAN1\t(1 << 4)\n" + "-#define I8K_HWMON_HAVE_FAN2\t(1 << 5)\n" + "-\n" + "-MODULE_AUTHOR(\"Massimo Dal Zotto (dz@debian.org)\");\n" + "-MODULE_DESCRIPTION(\"Driver for accessing SMM BIOS on Dell laptops\");\n" + "-MODULE_LICENSE(\"GPL\");\n" + "-\n" + "-static bool force;\n" + "-module_param(force, bool, 0);\n" + "-MODULE_PARM_DESC(force, \"Force loading without checking for supported models\");\n" + "-\n" + "-static bool ignore_dmi;\n" + "-module_param(ignore_dmi, bool, 0);\n" + "-MODULE_PARM_DESC(ignore_dmi, \"Continue probing hardware even if DMI data does not match\");\n" + "-\n" + "-static bool restricted;\n" + "-module_param(restricted, bool, 0);\n" + "-MODULE_PARM_DESC(restricted, \"Allow fan control if SYS_ADMIN capability set\");\n" + "-\n" + "-static bool power_status;\n" + "-module_param(power_status, bool, 0600);\n" + "-MODULE_PARM_DESC(power_status, \"Report power status in /proc/i8k\");\n" + "-\n" + "-static uint fan_mult;\n" + "-module_param(fan_mult, uint, 0);\n" + "-MODULE_PARM_DESC(fan_mult, \"Factor to multiply fan speed with (default: autodetect)\");\n" + "-\n" + "-static uint fan_max;\n" + "-module_param(fan_max, uint, 0);\n" + "-MODULE_PARM_DESC(fan_max, \"Maximum configurable fan speed (default: autodetect)\");\n" + "-\n" + "-static int i8k_open_fs(struct inode *inode, struct file *file);\n" + "-static long i8k_ioctl(struct file *, unsigned int, unsigned long);\n" + "-\n" + "-static const struct file_operations i8k_fops = {\n" + "-\t.owner\t\t= THIS_MODULE,\n" + "-\t.open\t\t= i8k_open_fs,\n" + "-\t.read\t\t= seq_read,\n" + "-\t.llseek\t\t= seq_lseek,\n" + "-\t.release\t= single_release,\n" + "-\t.unlocked_ioctl\t= i8k_ioctl,\n" + "-};\n" + "-\n" + "-struct smm_regs {\n" + "-\tunsigned int eax;\n" + "-\tunsigned int ebx __packed;\n" + "-\tunsigned int ecx __packed;\n" + "-\tunsigned int edx __packed;\n" + "-\tunsigned int esi __packed;\n" + "-\tunsigned int edi __packed;\n" + "-};\n" + "-\n" + "-static inline const char *i8k_get_dmi_data(int field)\n" + "-{\n" + "-\tconst char *dmi_data = dmi_get_system_info(field);\n" + "-\n" + "-\treturn dmi_data && *dmi_data ? dmi_data : \"?\";\n" + "-}\n" + "-\n" + "-/*\n" + "- * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.\n" + "- */\n" + "-static int i8k_smm(struct smm_regs *regs)\n" + "-{\n" + "-\tint rc;\n" + "-\tint eax = regs->eax;\n" + "-\tcpumask_var_t old_mask;\n" + "-\n" + "-\t/* SMM requires CPU 0 */\n" + "-\tif (!alloc_cpumask_var(&old_mask, GFP_KERNEL))\n" + "-\t\treturn -ENOMEM;\n" + "-\tcpumask_copy(old_mask, ¤t->cpus_allowed);\n" + "-\trc = set_cpus_allowed_ptr(current, cpumask_of(0));\n" + "-\tif (rc)\n" + "-\t\tgoto out;\n" + "-\tif (smp_processor_id() != 0) {\n" + "-\t\trc = -EBUSY;\n" + "-\t\tgoto out;\n" + "-\t}\n" + "-\n" + "-#if defined(CONFIG_X86_64)\n" + "-\tasm volatile(\"pushq %%rax\\n\\t\"\n" + "-\t\t\"movl 0(%%rax),%%edx\\n\\t\"\n" + "-\t\t\"pushq %%rdx\\n\\t\"\n" + "-\t\t\"movl 4(%%rax),%%ebx\\n\\t\"\n" + "-\t\t\"movl 8(%%rax),%%ecx\\n\\t\"\n" + "-\t\t\"movl 12(%%rax),%%edx\\n\\t\"\n" + "-\t\t\"movl 16(%%rax),%%esi\\n\\t\"\n" + "-\t\t\"movl 20(%%rax),%%edi\\n\\t\"\n" + "-\t\t\"popq %%rax\\n\\t\"\n" + "-\t\t\"out %%al,$0xb2\\n\\t\"\n" + "-\t\t\"out %%al,$0x84\\n\\t\"\n" + "-\t\t\"xchgq %%rax,(%%rsp)\\n\\t\"\n" + "-\t\t\"movl %%ebx,4(%%rax)\\n\\t\"\n" + "-\t\t\"movl %%ecx,8(%%rax)\\n\\t\"\n" + "-\t\t\"movl %%edx,12(%%rax)\\n\\t\"\n" + "-\t\t\"movl %%esi,16(%%rax)\\n\\t\"\n" + "-\t\t\"movl %%edi,20(%%rax)\\n\\t\"\n" + "-\t\t\"popq %%rdx\\n\\t\"\n" + "-\t\t\"movl %%edx,0(%%rax)\\n\\t\"\n" + "-\t\t\"pushfq\\n\\t\"\n" + "-\t\t\"popq %%rax\\n\\t\"\n" + "-\t\t\"andl $1,%%eax\\n\"\n" + "-\t\t: \"=a\"(rc)\n" + "-\t\t: \"a\"(regs)\n" + "-\t\t: \"%ebx\", \"%ecx\", \"%edx\", \"%esi\", \"%edi\", \"memory\");\n" + "-#else\n" + "-\tasm volatile(\"pushl %%eax\\n\\t\"\n" + "-\t \"movl 0(%%eax),%%edx\\n\\t\"\n" + "-\t \"push %%edx\\n\\t\"\n" + "-\t \"movl 4(%%eax),%%ebx\\n\\t\"\n" + "-\t \"movl 8(%%eax),%%ecx\\n\\t\"\n" + "-\t \"movl 12(%%eax),%%edx\\n\\t\"\n" + "-\t \"movl 16(%%eax),%%esi\\n\\t\"\n" + "-\t \"movl 20(%%eax),%%edi\\n\\t\"\n" + "-\t \"popl %%eax\\n\\t\"\n" + "-\t \"out %%al,$0xb2\\n\\t\"\n" + "-\t \"out %%al,$0x84\\n\\t\"\n" + "-\t \"xchgl %%eax,(%%esp)\\n\\t\"\n" + "-\t \"movl %%ebx,4(%%eax)\\n\\t\"\n" + "-\t \"movl %%ecx,8(%%eax)\\n\\t\"\n" + "-\t \"movl %%edx,12(%%eax)\\n\\t\"\n" + "-\t \"movl %%esi,16(%%eax)\\n\\t\"\n" + "-\t \"movl %%edi,20(%%eax)\\n\\t\"\n" + "-\t \"popl %%edx\\n\\t\"\n" + "-\t \"movl %%edx,0(%%eax)\\n\\t\"\n" + "-\t \"lahf\\n\\t\"\n" + "-\t \"shrl $8,%%eax\\n\\t\"\n" + "-\t \"andl $1,%%eax\\n\"\n" + "-\t : \"=a\"(rc)\n" + "-\t : \"a\"(regs)\n" + "-\t : \"%ebx\", \"%ecx\", \"%edx\", \"%esi\", \"%edi\", \"memory\");\n" + "-#endif\n" + "-\tif (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)\n" + "-\t\trc = -EINVAL;\n" + "-\n" + "-out:\n" + "-\tset_cpus_allowed_ptr(current, old_mask);\n" + "-\tfree_cpumask_var(old_mask);\n" + "-\treturn rc;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the Fn key status.\n" + "- */\n" + "-static int i8k_get_fn_status(void)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };\n" + "-\tint rc;\n" + "-\n" + "-\trc = i8k_smm(®s);\n" + "-\tif (rc < 0)\n" + "-\t\treturn rc;\n" + "-\n" + "-\tswitch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {\n" + "-\tcase I8K_FN_UP:\n" + "-\t\treturn I8K_VOL_UP;\n" + "-\tcase I8K_FN_DOWN:\n" + "-\t\treturn I8K_VOL_DOWN;\n" + "-\tcase I8K_FN_MUTE:\n" + "-\t\treturn I8K_VOL_MUTE;\n" + "-\tdefault:\n" + "-\t\treturn 0;\n" + "-\t}\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the power status.\n" + "- */\n" + "-static int i8k_get_power_status(void)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };\n" + "-\tint rc;\n" + "-\n" + "-\trc = i8k_smm(®s);\n" + "-\tif (rc < 0)\n" + "-\t\treturn rc;\n" + "-\n" + "-\treturn (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the fan status.\n" + "- */\n" + "-static int i8k_get_fan_status(int fan)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };\n" + "-\n" + "-\tregs.ebx = fan & 0xff;\n" + "-\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the fan speed in RPM.\n" + "- */\n" + "-static int i8k_get_fan_speed(int fan)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };\n" + "-\n" + "-\tregs.ebx = fan & 0xff;\n" + "-\treturn i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the fan type.\n" + "- */\n" + "-static int i8k_get_fan_type(int fan)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };\n" + "-\n" + "-\tregs.ebx = fan & 0xff;\n" + "-\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the fan nominal rpm for specific fan speed.\n" + "- */\n" + "-static int i8k_get_fan_nominal_speed(int fan, int speed)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };\n" + "-\n" + "-\tregs.ebx = (fan & 0xff) | (speed << 8);\n" + "-\treturn i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Set the fan speed (off, low, high). Returns the new fan status.\n" + "- */\n" + "-static int i8k_set_fan(int fan, int speed)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };\n" + "-\n" + "-\tspeed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);\n" + "-\tregs.ebx = (fan & 0xff) | (speed << 8);\n" + "-\n" + "-\treturn i8k_smm(®s) ? : i8k_get_fan_status(fan);\n" + "-}\n" + "-\n" + "-static int i8k_get_temp_type(int sensor)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };\n" + "-\n" + "-\tregs.ebx = sensor & 0xff;\n" + "-\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Read the cpu temperature.\n" + "- */\n" + "-static int _i8k_get_temp(int sensor)\n" + "-{\n" + "-\tstruct smm_regs regs = {\n" + "-\t\t.eax = I8K_SMM_GET_TEMP,\n" + "-\t\t.ebx = sensor & 0xff,\n" + "-\t};\n" + "-\n" + "-\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "-}\n" + "-\n" + "-static int i8k_get_temp(int sensor)\n" + "-{\n" + "-\tint temp = _i8k_get_temp(sensor);\n" + "-\n" + "-\t/*\n" + "-\t * Sometimes the temperature sensor returns 0x99, which is out of range.\n" + "-\t * In this case we retry (once) before returning an error.\n" + "-\t # 1003655137 00000058 00005a4b\n" + "-\t # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees\n" + "-\t # 1003655139 00000054 00005c52\n" + "-\t */\n" + "-\tif (temp == 0x99) {\n" + "-\t\tmsleep(100);\n" + "-\t\ttemp = _i8k_get_temp(sensor);\n" + "-\t}\n" + "-\t/*\n" + "-\t * Return -ENODATA for all invalid temperatures.\n" + "-\t *\n" + "-\t * Known instances are the 0x99 value as seen above as well as\n" + "-\t * 0xc1 (193), which may be returned when trying to read the GPU\n" + "-\t * temperature if the system supports a GPU and it is currently\n" + "-\t * turned off.\n" + "-\t */\n" + "-\tif (temp > I8K_MAX_TEMP)\n" + "-\t\treturn -ENODATA;\n" + "-\n" + "-\treturn temp;\n" + "-}\n" + "-\n" + "-static int i8k_get_dell_signature(int req_fn)\n" + "-{\n" + "-\tstruct smm_regs regs = { .eax = req_fn, };\n" + "-\tint rc;\n" + "-\n" + "-\trc = i8k_smm(®s);\n" + "-\tif (rc < 0)\n" + "-\t\treturn rc;\n" + "-\n" + "-\treturn regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;\n" + "-}\n" + "-\n" + "-static int\n" + "-i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)\n" + "-{\n" + "-\tint val = 0;\n" + "-\tint speed;\n" + "-\tunsigned char buff[16];\n" + "-\tint __user *argp = (int __user *)arg;\n" + "-\n" + "-\tif (!argp)\n" + "-\t\treturn -EINVAL;\n" + "-\n" + "-\tswitch (cmd) {\n" + "-\tcase I8K_BIOS_VERSION:\n" + "-\t\tval = (bios_version[0] << 16) |\n" + "-\t\t\t\t(bios_version[1] << 8) | bios_version[2];\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_MACHINE_ID:\n" + "-\t\tmemset(buff, 0, 16);\n" + "-\t\tstrlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),\n" + "-\t\t\tsizeof(buff));\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_FN_STATUS:\n" + "-\t\tval = i8k_get_fn_status();\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_POWER_STATUS:\n" + "-\t\tval = i8k_get_power_status();\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_GET_TEMP:\n" + "-\t\tval = i8k_get_temp(0);\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_GET_SPEED:\n" + "-\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tval = i8k_get_fan_speed(val);\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_GET_FAN:\n" + "-\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tval = i8k_get_fan_status(val);\n" + "-\t\tbreak;\n" + "-\n" + "-\tcase I8K_SET_FAN:\n" + "-\t\tif (restricted && !capable(CAP_SYS_ADMIN))\n" + "-\t\t\treturn -EPERM;\n" + "-\n" + "-\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tif (copy_from_user(&speed, argp + 1, sizeof(int)))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tval = i8k_set_fan(val, speed);\n" + "-\t\tbreak;\n" + "-\n" + "-\tdefault:\n" + "-\t\treturn -EINVAL;\n" + "-\t}\n" + "-\n" + "-\tif (val < 0)\n" + "-\t\treturn val;\n" + "-\n" + "-\tswitch (cmd) {\n" + "-\tcase I8K_BIOS_VERSION:\n" + "-\t\tif (copy_to_user(argp, &val, 4))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tbreak;\n" + "-\tcase I8K_MACHINE_ID:\n" + "-\t\tif (copy_to_user(argp, buff, 16))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tbreak;\n" + "-\tdefault:\n" + "-\t\tif (copy_to_user(argp, &val, sizeof(int)))\n" + "-\t\t\treturn -EFAULT;\n" + "-\n" + "-\t\tbreak;\n" + "-\t}\n" + "-\n" + "-\treturn 0;\n" + "-}\n" + "-\n" + "-static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)\n" + "-{\n" + "-\tlong ret;\n" + "-\n" + "-\tmutex_lock(&i8k_mutex);\n" + "-\tret = i8k_ioctl_unlocked(fp, cmd, arg);\n" + "-\tmutex_unlock(&i8k_mutex);\n" + "-\n" + "-\treturn ret;\n" + "-}\n" + "-\n" + "-/*\n" + "- * Print the information for /proc/i8k.\n" + "- */\n" + "-static int i8k_proc_show(struct seq_file *seq, void *offset)\n" + "-{\n" + "-\tint fn_key, cpu_temp, ac_power;\n" + "-\tint left_fan, right_fan, left_speed, right_speed;\n" + "-\n" + "-\tcpu_temp\t= i8k_get_temp(0);\t\t\t/* 11100 \302\265s */\n" + "-\tleft_fan\t= i8k_get_fan_status(I8K_FAN_LEFT);\t/* 580 \302\265s */\n" + "-\tright_fan\t= i8k_get_fan_status(I8K_FAN_RIGHT);\t/* 580 \302\265s */\n" + "-\tleft_speed\t= i8k_get_fan_speed(I8K_FAN_LEFT);\t/* 580 \302\265s */\n" + "-\tright_speed\t= i8k_get_fan_speed(I8K_FAN_RIGHT);\t/* 580 \302\265s */\n" + "-\tfn_key\t\t= i8k_get_fn_status();\t\t\t/* 750 \302\265s */\n" + "-\tif (power_status)\n" + "-\t\tac_power = i8k_get_power_status();\t\t/* 14700 \302\265s */\n" + "-\telse\n" + "-\t\tac_power = -1;\n" + "-\n" + "-\t/*\n" + "-\t * Info:\n" + "-\t *\n" + "-\t * 1) Format version (this will change if format changes)\n" + "-\t * 2) BIOS version\n" + "-\t * 3) BIOS machine ID\n" + "-\t * 4) Cpu temperature\n" + "-\t * 5) Left fan status\n" + "-\t * 6) Right fan status\n" + "-\t * 7) Left fan speed\n" + "-\t * 8) Right fan speed\n" + "-\t * 9) AC power\n" + "-\t * 10) Fn Key status\n" + "-\t */\n" + "-\treturn seq_printf(seq, \"%s %s %s %d %d %d %d %d %d %d\\n\",\n" + "-\t\t\t I8K_PROC_FMT,\n" + "-\t\t\t bios_version,\n" + "-\t\t\t i8k_get_dmi_data(DMI_PRODUCT_SERIAL),\n" + "-\t\t\t cpu_temp,\n" + "-\t\t\t left_fan, right_fan, left_speed, right_speed,\n" + "-\t\t\t ac_power, fn_key);\n" + "-}\n" + "-\n" + "-static int i8k_open_fs(struct inode *inode, struct file *file)\n" + "-{\n" + "-\treturn single_open(file, i8k_proc_show, NULL);\n" + "-}\n" + "-\n" + "-\n" + "-/*\n" + "- * Hwmon interface\n" + "- */\n" + "-\n" + "-static ssize_t i8k_hwmon_show_temp_label(struct device *dev,\n" + "-\t\t\t\t\t struct device_attribute *devattr,\n" + "-\t\t\t\t\t char *buf)\n" + "-{\n" + "-\tstatic const char * const labels[] = {\n" + "-\t\t\"CPU\",\n" + "-\t\t\"GPU\",\n" + "-\t\t\"SODIMM\",\n" + "-\t\t\"Other\",\n" + "-\t\t\"Ambient\",\n" + "-\t\t\"Other\",\n" + "-\t};\n" + "-\tint index = to_sensor_dev_attr(devattr)->index;\n" + "-\tint type;\n" + "-\n" + "-\ttype = i8k_get_temp_type(index);\n" + "-\tif (type < 0)\n" + "-\t\treturn type;\n" + "-\tif (type >= ARRAY_SIZE(labels))\n" + "-\t\ttype = ARRAY_SIZE(labels) - 1;\n" + "-\treturn sprintf(buf, \"%s\\n\", labels[type]);\n" + "-}\n" + "-\n" + "-static ssize_t i8k_hwmon_show_temp(struct device *dev,\n" + "-\t\t\t\t struct device_attribute *devattr,\n" + "-\t\t\t\t char *buf)\n" + "-{\n" + "-\tint index = to_sensor_dev_attr(devattr)->index;\n" + "-\tint temp;\n" + "-\n" + "-\ttemp = i8k_get_temp(index);\n" + "-\tif (temp < 0)\n" + "-\t\treturn temp;\n" + "-\treturn sprintf(buf, \"%d\\n\", temp * 1000);\n" + "-}\n" + "-\n" + "-static ssize_t i8k_hwmon_show_fan_label(struct device *dev,\n" + "-\t\t\t\t\tstruct device_attribute *devattr,\n" + "-\t\t\t\t\tchar *buf)\n" + "-{\n" + "-\tstatic const char * const labels[] = {\n" + "-\t\t\"Processor Fan\",\n" + "-\t\t\"Motherboard Fan\",\n" + "-\t\t\"Video Fan\",\n" + "-\t\t\"Power Supply Fan\",\n" + "-\t\t\"Chipset Fan\",\n" + "-\t\t\"Other Fan\",\n" + "-\t};\n" + "-\tint index = to_sensor_dev_attr(devattr)->index;\n" + "-\tbool dock = false;\n" + "-\tint type;\n" + "-\n" + "-\ttype = i8k_get_fan_type(index);\n" + "-\tif (type < 0)\n" + "-\t\treturn type;\n" + "-\n" + "-\tif (type & 0x10) {\n" + "-\t\tdock = true;\n" + "-\t\ttype &= 0x0F;\n" + "-\t}\n" + "-\n" + "-\tif (type >= ARRAY_SIZE(labels))\n" + "-\t\ttype = (ARRAY_SIZE(labels) - 1);\n" + "-\n" + "-\treturn sprintf(buf, \"%s%s\\n\", (dock ? \"Docking \" : \"\"), labels[type]);\n" + "-}\n" + "-\n" + "-static ssize_t i8k_hwmon_show_fan(struct device *dev,\n" + "-\t\t\t\t struct device_attribute *devattr,\n" + "-\t\t\t\t char *buf)\n" + "-{\n" + "-\tint index = to_sensor_dev_attr(devattr)->index;\n" + "-\tint fan_speed;\n" + "-\n" + "-\tfan_speed = i8k_get_fan_speed(index);\n" + "-\tif (fan_speed < 0)\n" + "-\t\treturn fan_speed;\n" + "-\treturn sprintf(buf, \"%d\\n\", fan_speed);\n" + "-}\n" + "-\n" + "-static ssize_t i8k_hwmon_show_pwm(struct device *dev,\n" + "-\t\t\t\t struct device_attribute *devattr,\n" + "-\t\t\t\t char *buf)\n" + "-{\n" + "-\tint index = to_sensor_dev_attr(devattr)->index;\n" + "-\tint status;\n" + "-\n" + "-\tstatus = i8k_get_fan_status(index);\n" + "-\tif (status < 0)\n" + "-\t\treturn -EIO;\n" + "-\treturn sprintf(buf, \"%d\\n\", clamp_val(status * i8k_pwm_mult, 0, 255));\n" + "-}\n" + "-\n" + "-static ssize_t i8k_hwmon_set_pwm(struct device *dev,\n" + "-\t\t\t\t struct device_attribute *attr,\n" + "-\t\t\t\t const char *buf, size_t count)\n" + "-{\n" + "-\tint index = to_sensor_dev_attr(attr)->index;\n" + "-\tunsigned long val;\n" + "-\tint err;\n" + "-\n" + "-\terr = kstrtoul(buf, 10, &val);\n" + "-\tif (err)\n" + "-\t\treturn err;\n" + "-\tval = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);\n" + "-\n" + "-\tmutex_lock(&i8k_mutex);\n" + "-\terr = i8k_set_fan(index, val);\n" + "-\tmutex_unlock(&i8k_mutex);\n" + "-\n" + "-\treturn err < 0 ? -EIO : count;\n" + "-}\n" + "-\n" + "-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);\n" + "-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "-\t\t\t 0);\n" + "-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);\n" + "-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "-\t\t\t 1);\n" + "-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);\n" + "-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "-\t\t\t 2);\n" + "-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);\n" + "-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "-\t\t\t 3);\n" + "-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);\n" + "-static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,\n" + "-\t\t\t 0);\n" + "-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,\n" + "-\t\t\t i8k_hwmon_set_pwm, 0);\n" + "-static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,\n" + "-\t\t\t 1);\n" + "-static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,\n" + "-\t\t\t 1);\n" + "-static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,\n" + "-\t\t\t i8k_hwmon_set_pwm, 1);\n" + "-\n" + "-static struct attribute *i8k_attrs[] = {\n" + "-\t&sensor_dev_attr_temp1_input.dev_attr.attr,\t/* 0 */\n" + "-\t&sensor_dev_attr_temp1_label.dev_attr.attr,\t/* 1 */\n" + "-\t&sensor_dev_attr_temp2_input.dev_attr.attr,\t/* 2 */\n" + "-\t&sensor_dev_attr_temp2_label.dev_attr.attr,\t/* 3 */\n" + "-\t&sensor_dev_attr_temp3_input.dev_attr.attr,\t/* 4 */\n" + "-\t&sensor_dev_attr_temp3_label.dev_attr.attr,\t/* 5 */\n" + "-\t&sensor_dev_attr_temp4_input.dev_attr.attr,\t/* 6 */\n" + "-\t&sensor_dev_attr_temp4_label.dev_attr.attr,\t/* 7 */\n" + "-\t&sensor_dev_attr_fan1_input.dev_attr.attr,\t/* 8 */\n" + "-\t&sensor_dev_attr_fan1_label.dev_attr.attr,\t/* 9 */\n" + "-\t&sensor_dev_attr_pwm1.dev_attr.attr,\t\t/* 10 */\n" + "-\t&sensor_dev_attr_fan2_input.dev_attr.attr,\t/* 11 */\n" + "-\t&sensor_dev_attr_fan2_label.dev_attr.attr,\t/* 12 */\n" + "-\t&sensor_dev_attr_pwm2.dev_attr.attr,\t\t/* 13 */\n" + "-\tNULL\n" + "-};\n" + "-\n" + "-static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,\n" + "-\t\t\t int index)\n" + "-{\n" + "-\tif (index >= 0 && index <= 1 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))\n" + "-\t\treturn 0;\n" + "-\tif (index >= 2 && index <= 3 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))\n" + "-\t\treturn 0;\n" + "-\tif (index >= 4 && index <= 5 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))\n" + "-\t\treturn 0;\n" + "-\tif (index >= 6 && index <= 7 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))\n" + "-\t\treturn 0;\n" + "-\tif (index >= 8 && index <= 10 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))\n" + "-\t\treturn 0;\n" + "-\tif (index >= 11 && index <= 13 &&\n" + "-\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))\n" + "-\t\treturn 0;\n" + "-\n" + "-\treturn attr->mode;\n" + "-}\n" + "-\n" + "-static const struct attribute_group i8k_group = {\n" + "-\t.attrs = i8k_attrs,\n" + "-\t.is_visible = i8k_is_visible,\n" + "-};\n" + "-__ATTRIBUTE_GROUPS(i8k);\n" + "-\n" + "-static int __init i8k_init_hwmon(void)\n" + "-{\n" + "-\tint err;\n" + "-\n" + "-\ti8k_hwmon_flags = 0;\n" + "-\n" + "-\t/* CPU temperature attributes, if temperature type is OK */\n" + "-\terr = i8k_get_temp_type(0);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;\n" + "-\t/* check for additional temperature sensors */\n" + "-\terr = i8k_get_temp_type(1);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;\n" + "-\terr = i8k_get_temp_type(2);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;\n" + "-\terr = i8k_get_temp_type(3);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;\n" + "-\n" + "-\t/* First fan attributes, if fan type is OK */\n" + "-\terr = i8k_get_fan_type(0);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;\n" + "-\n" + "-\t/* Second fan attributes, if fan type is OK */\n" + "-\terr = i8k_get_fan_type(1);\n" + "-\tif (err >= 0)\n" + "-\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;\n" + "-\n" + "-\ti8k_hwmon_dev = hwmon_device_register_with_groups(NULL, \"i8k\", NULL,\n" + "-\t\t\t\t\t\t\t i8k_groups);\n" + "-\tif (IS_ERR(i8k_hwmon_dev)) {\n" + "-\t\terr = PTR_ERR(i8k_hwmon_dev);\n" + "-\t\ti8k_hwmon_dev = NULL;\n" + "-\t\tpr_err(\"hwmon registration failed (%d)\\n\", err);\n" + "-\t\treturn err;\n" + "-\t}\n" + "-\treturn 0;\n" + "-}\n" + "-\n" + "-struct i8k_config_data {\n" + "-\tuint fan_mult;\n" + "-\tuint fan_max;\n" + "-};\n" + "-\n" + "-enum i8k_configs {\n" + "-\tDELL_LATITUDE_D520,\n" + "-\tDELL_PRECISION_490,\n" + "-\tDELL_STUDIO,\n" + "-\tDELL_XPS,\n" + "-};\n" + "-\n" + "-static const struct i8k_config_data i8k_config_data[] = {\n" + "-\t[DELL_LATITUDE_D520] = {\n" + "-\t\t.fan_mult = 1,\n" + "-\t\t.fan_max = I8K_FAN_TURBO,\n" + "-\t},\n" + "-\t[DELL_PRECISION_490] = {\n" + "-\t\t.fan_mult = 1,\n" + "-\t\t.fan_max = I8K_FAN_TURBO,\n" + "-\t},\n" + "-\t[DELL_STUDIO] = {\n" + "-\t\t.fan_mult = 1,\n" + "-\t\t.fan_max = I8K_FAN_HIGH,\n" + "-\t},\n" + "-\t[DELL_XPS] = {\n" + "-\t\t.fan_mult = 1,\n" + "-\t\t.fan_max = I8K_FAN_HIGH,\n" + "-\t},\n" + "-};\n" + "-\n" + "-static struct dmi_system_id i8k_dmi_table[] __initdata = {\n" + "-\t{\n" + "-\t\t.ident = \"Dell Inspiron\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Computer\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Inspiron\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Latitude\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Computer\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Inspiron 2\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Inspiron\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Latitude D520\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude D520\"),\n" + "-\t\t},\n" + "-\t\t.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Latitude 2\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\t/* UK Inspiron 6400 */\n" + "-\t\t.ident = \"Dell Inspiron 3\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MM061\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Inspiron 3\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MP061\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Precision 490\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME,\n" + "-\t\t\t\t \"Precision WorkStation 490\"),\n" + "-\t\t},\n" + "-\t\t.driver_data = (void *)&i8k_config_data[DELL_PRECISION_490],\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Precision\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Precision\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Vostro\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Vostro\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell XPS421\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"XPS L421X\"),\n" + "-\t\t},\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell Studio\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Studio\"),\n" + "-\t\t},\n" + "-\t\t.driver_data = (void *)&i8k_config_data[DELL_STUDIO],\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell XPS 13\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"XPS13\"),\n" + "-\t\t},\n" + "-\t\t.driver_data = (void *)&i8k_config_data[DELL_XPS],\n" + "-\t},\n" + "-\t{\n" + "-\t\t.ident = \"Dell XPS M140\",\n" + "-\t\t.matches = {\n" + "-\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "-\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MXC051\"),\n" + "-\t\t},\n" + "-\t\t.driver_data = (void *)&i8k_config_data[DELL_XPS],\n" + "-\t},\n" + "-\t{ }\n" + "-};\n" + "-\n" + "-MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);\n" + "-\n" + "-/*\n" + "- * Probe for the presence of a supported laptop.\n" + "- */\n" + "-static int __init i8k_probe(void)\n" + "-{\n" + "-\tconst struct dmi_system_id *id;\n" + "-\tint fan, ret;\n" + "-\n" + "-\t/*\n" + "-\t * Get DMI information\n" + "-\t */\n" + "-\tif (!dmi_check_system(i8k_dmi_table)) {\n" + "-\t\tif (!ignore_dmi && !force)\n" + "-\t\t\treturn -ENODEV;\n" + "-\n" + "-\t\tpr_info(\"not running on a supported Dell system.\\n\");\n" + "-\t\tpr_info(\"vendor=%s, model=%s, version=%s\\n\",\n" + "-\t\t\ti8k_get_dmi_data(DMI_SYS_VENDOR),\n" + "-\t\t\ti8k_get_dmi_data(DMI_PRODUCT_NAME),\n" + "-\t\t\ti8k_get_dmi_data(DMI_BIOS_VERSION));\n" + "-\t}\n" + "-\n" + "-\tstrlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),\n" + "-\t\tsizeof(bios_version));\n" + "-\n" + "-\t/*\n" + "-\t * Get SMM Dell signature\n" + "-\t */\n" + "-\tif (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&\n" + "-\t i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {\n" + "-\t\tpr_err(\"unable to get SMM Dell signature\\n\");\n" + "-\t\tif (!force)\n" + "-\t\t\treturn -ENODEV;\n" + "-\t}\n" + "-\n" + "-\t/*\n" + "-\t * Set fan multiplier and maximal fan speed from dmi config\n" + "-\t * Values specified in module parameters override values from dmi\n" + "-\t */\n" + "-\tid = dmi_first_match(i8k_dmi_table);\n" + "-\tif (id && id->driver_data) {\n" + "-\t\tconst struct i8k_config_data *conf = id->driver_data;\n" + "-\t\tif (!fan_mult && conf->fan_mult)\n" + "-\t\t\tfan_mult = conf->fan_mult;\n" + "-\t\tif (!fan_max && conf->fan_max)\n" + "-\t\t\tfan_max = conf->fan_max;\n" + "-\t}\n" + "-\n" + "-\ti8k_fan_max = fan_max ? : I8K_FAN_HIGH;\t/* Must not be 0 */\n" + "-\ti8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);\n" + "-\n" + "-\tif (!fan_mult) {\n" + "-\t\t/*\n" + "-\t\t * Autodetect fan multiplier based on nominal rpm\n" + "-\t\t * If fan reports rpm value too high then set multiplier to 1\n" + "-\t\t */\n" + "-\t\tfor (fan = 0; fan < 2; ++fan) {\n" + "-\t\t\tret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);\n" + "-\t\t\tif (ret < 0)\n" + "-\t\t\t\tcontinue;\n" + "-\t\t\tif (ret > I8K_FAN_MAX_RPM)\n" + "-\t\t\t\ti8k_fan_mult = 1;\n" + "-\t\t\tbreak;\n" + "-\t\t}\n" + "-\t} else {\n" + "-\t\t/* Fan multiplier was specified in module param or in dmi */\n" + "-\t\ti8k_fan_mult = fan_mult;\n" + "-\t}\n" + "-\n" + "-\treturn 0;\n" + "-}\n" + "-\n" + "-static int __init i8k_init(void)\n" + "-{\n" + "-\tstruct proc_dir_entry *proc_i8k;\n" + "-\tint err;\n" + "-\n" + "-\t/* Are we running on an supported laptop? */\n" + "-\tif (i8k_probe())\n" + "-\t\treturn -ENODEV;\n" + "-\n" + "-\t/* Register the proc entry */\n" + "-\tproc_i8k = proc_create(\"i8k\", 0, NULL, &i8k_fops);\n" + "-\tif (!proc_i8k)\n" + "-\t\treturn -ENOENT;\n" + "-\n" + "-\terr = i8k_init_hwmon();\n" + "-\tif (err)\n" + "-\t\tgoto exit_remove_proc;\n" + "-\n" + "-\treturn 0;\n" + "-\n" + "- exit_remove_proc:\n" + "-\tremove_proc_entry(\"i8k\", NULL);\n" + "-\treturn err;\n" + "-}\n" + "-\n" + "-static void __exit i8k_exit(void)\n" + "-{\n" + "-\thwmon_device_unregister(i8k_hwmon_dev);\n" + "-\tremove_proc_entry(\"i8k\", NULL);\n" + "-}\n" + "-\n" + "-module_init(i8k_init);\n" + "-module_exit(i8k_exit);\n" + "diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile\n" + "index 6c94147..1c3e458 100644\n" + "--- a/drivers/hwmon/Makefile\n" + "+++ b/drivers/hwmon/Makefile\n" + "@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)\t+= w83l785ts.o\n" + " obj-$(CONFIG_SENSORS_W83L786NG)\t+= w83l786ng.o\n" + " obj-$(CONFIG_SENSORS_WM831X)\t+= wm831x-hwmon.o\n" + " obj-$(CONFIG_SENSORS_WM8350)\t+= wm8350-hwmon.o\n" + "+obj-$(CONFIG_I8K)\t\t+= dell-smm-hwmon.o\n" + " \n" + " obj-$(CONFIG_PMBUS)\t\t+= pmbus/\n" + " \n" + "diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c\n" + "new file mode 100644\n" + "index 0000000..2b04e4f\n" + "--- /dev/null\n" + "+++ b/drivers/hwmon/dell-smm-hwmon.c\n" + "@@ -0,0 +1,1007 @@\n" + "+/*\n" + "+ * dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops.\n" + "+ *\n" + "+ * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>\n" + "+ *\n" + "+ * Hwmon integration:\n" + "+ * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>\n" + "+ * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net>\n" + "+ * Copyright (C) 2014, 2015 Pali Roh\303\241r <pali.rohar@gmail.com>\n" + "+ *\n" + "+ * This program is free software; you can redistribute it and/or modify it\n" + "+ * under the terms of the GNU General Public License as published by the\n" + "+ * Free Software Foundation; either version 2, or (at your option) any\n" + "+ * later version.\n" + "+ *\n" + "+ * This program is distributed in the hope that it will be useful, but\n" + "+ * WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + "+ * General Public License for more details.\n" + "+ */\n" + "+\n" + "+#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n" + "+\n" + "+#include <linux/delay.h>\n" + "+#include <linux/module.h>\n" + "+#include <linux/types.h>\n" + "+#include <linux/init.h>\n" + "+#include <linux/proc_fs.h>\n" + "+#include <linux/seq_file.h>\n" + "+#include <linux/dmi.h>\n" + "+#include <linux/capability.h>\n" + "+#include <linux/mutex.h>\n" + "+#include <linux/hwmon.h>\n" + "+#include <linux/hwmon-sysfs.h>\n" + "+#include <linux/uaccess.h>\n" + "+#include <linux/io.h>\n" + "+#include <linux/sched.h>\n" + "+\n" + "+#include <linux/i8k.h>\n" + "+\n" + "+#define I8K_SMM_FN_STATUS\t0x0025\n" + "+#define I8K_SMM_POWER_STATUS\t0x0069\n" + "+#define I8K_SMM_SET_FAN\t\t0x01a3\n" + "+#define I8K_SMM_GET_FAN\t\t0x00a3\n" + "+#define I8K_SMM_GET_SPEED\t0x02a3\n" + "+#define I8K_SMM_GET_FAN_TYPE\t0x03a3\n" + "+#define I8K_SMM_GET_NOM_SPEED\t0x04a3\n" + "+#define I8K_SMM_GET_TEMP\t0x10a3\n" + "+#define I8K_SMM_GET_TEMP_TYPE\t0x11a3\n" + "+#define I8K_SMM_GET_DELL_SIG1\t0xfea3\n" + "+#define I8K_SMM_GET_DELL_SIG2\t0xffa3\n" + "+\n" + "+#define I8K_FAN_MULT\t\t30\n" + "+#define I8K_FAN_MAX_RPM\t\t30000\n" + "+#define I8K_MAX_TEMP\t\t127\n" + "+\n" + "+#define I8K_FN_NONE\t\t0x00\n" + "+#define I8K_FN_UP\t\t0x01\n" + "+#define I8K_FN_DOWN\t\t0x02\n" + "+#define I8K_FN_MUTE\t\t0x04\n" + "+#define I8K_FN_MASK\t\t0x07\n" + "+#define I8K_FN_SHIFT\t\t8\n" + "+\n" + "+#define I8K_POWER_AC\t\t0x05\n" + "+#define I8K_POWER_BATTERY\t0x01\n" + "+\n" + "+static DEFINE_MUTEX(i8k_mutex);\n" + "+static char bios_version[4];\n" + "+static struct device *i8k_hwmon_dev;\n" + "+static u32 i8k_hwmon_flags;\n" + "+static uint i8k_fan_mult = I8K_FAN_MULT;\n" + "+static uint i8k_pwm_mult;\n" + "+static uint i8k_fan_max = I8K_FAN_HIGH;\n" + "+\n" + "+#define I8K_HWMON_HAVE_TEMP1\t(1 << 0)\n" + "+#define I8K_HWMON_HAVE_TEMP2\t(1 << 1)\n" + "+#define I8K_HWMON_HAVE_TEMP3\t(1 << 2)\n" + "+#define I8K_HWMON_HAVE_TEMP4\t(1 << 3)\n" + "+#define I8K_HWMON_HAVE_FAN1\t(1 << 4)\n" + "+#define I8K_HWMON_HAVE_FAN2\t(1 << 5)\n" + "+\n" + "+MODULE_AUTHOR(\"Massimo Dal Zotto (dz@debian.org)\");\n" + "+MODULE_AUTHOR(\"Pali Roh\303\241r <pali.rohar@gmail.com>\");\n" + "+MODULE_DESCRIPTION(\"Driver for accessing SMM BIOS on Dell laptops\");\n" + "+MODULE_LICENSE(\"GPL\");\n" + "+MODULE_ALIAS(\"i8k\");\n" + "+\n" + "+static bool force;\n" + "+module_param(force, bool, 0);\n" + "+MODULE_PARM_DESC(force, \"Force loading without checking for supported models\");\n" + "+\n" + "+static bool ignore_dmi;\n" + "+module_param(ignore_dmi, bool, 0);\n" + "+MODULE_PARM_DESC(ignore_dmi, \"Continue probing hardware even if DMI data does not match\");\n" + "+\n" + "+static bool restricted;\n" + "+module_param(restricted, bool, 0);\n" + "+MODULE_PARM_DESC(restricted, \"Allow fan control if SYS_ADMIN capability set\");\n" + "+\n" + "+static bool power_status;\n" + "+module_param(power_status, bool, 0600);\n" + "+MODULE_PARM_DESC(power_status, \"Report power status in /proc/i8k\");\n" + "+\n" + "+static uint fan_mult;\n" + "+module_param(fan_mult, uint, 0);\n" + "+MODULE_PARM_DESC(fan_mult, \"Factor to multiply fan speed with (default: autodetect)\");\n" + "+\n" + "+static uint fan_max;\n" + "+module_param(fan_max, uint, 0);\n" + "+MODULE_PARM_DESC(fan_max, \"Maximum configurable fan speed (default: autodetect)\");\n" + "+\n" + "+static int i8k_open_fs(struct inode *inode, struct file *file);\n" + "+static long i8k_ioctl(struct file *, unsigned int, unsigned long);\n" + "+\n" + "+static const struct file_operations i8k_fops = {\n" + "+\t.owner\t\t= THIS_MODULE,\n" + "+\t.open\t\t= i8k_open_fs,\n" + "+\t.read\t\t= seq_read,\n" + "+\t.llseek\t\t= seq_lseek,\n" + "+\t.release\t= single_release,\n" + "+\t.unlocked_ioctl\t= i8k_ioctl,\n" + "+};\n" + "+\n" + "+struct smm_regs {\n" + "+\tunsigned int eax;\n" + "+\tunsigned int ebx __packed;\n" + "+\tunsigned int ecx __packed;\n" + "+\tunsigned int edx __packed;\n" + "+\tunsigned int esi __packed;\n" + "+\tunsigned int edi __packed;\n" + "+};\n" + "+\n" + "+static inline const char *i8k_get_dmi_data(int field)\n" + "+{\n" + "+\tconst char *dmi_data = dmi_get_system_info(field);\n" + "+\n" + "+\treturn dmi_data && *dmi_data ? dmi_data : \"?\";\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.\n" + "+ */\n" + "+static int i8k_smm(struct smm_regs *regs)\n" + "+{\n" + "+\tint rc;\n" + "+\tint eax = regs->eax;\n" + "+\tcpumask_var_t old_mask;\n" + "+\n" + "+\t/* SMM requires CPU 0 */\n" + "+\tif (!alloc_cpumask_var(&old_mask, GFP_KERNEL))\n" + "+\t\treturn -ENOMEM;\n" + "+\tcpumask_copy(old_mask, ¤t->cpus_allowed);\n" + "+\trc = set_cpus_allowed_ptr(current, cpumask_of(0));\n" + "+\tif (rc)\n" + "+\t\tgoto out;\n" + "+\tif (smp_processor_id() != 0) {\n" + "+\t\trc = -EBUSY;\n" + "+\t\tgoto out;\n" + "+\t}\n" + "+\n" + "+#if defined(CONFIG_X86_64)\n" + "+\tasm volatile(\"pushq %%rax\\n\\t\"\n" + "+\t\t\"movl 0(%%rax),%%edx\\n\\t\"\n" + "+\t\t\"pushq %%rdx\\n\\t\"\n" + "+\t\t\"movl 4(%%rax),%%ebx\\n\\t\"\n" + "+\t\t\"movl 8(%%rax),%%ecx\\n\\t\"\n" + "+\t\t\"movl 12(%%rax),%%edx\\n\\t\"\n" + "+\t\t\"movl 16(%%rax),%%esi\\n\\t\"\n" + "+\t\t\"movl 20(%%rax),%%edi\\n\\t\"\n" + "+\t\t\"popq %%rax\\n\\t\"\n" + "+\t\t\"out %%al,$0xb2\\n\\t\"\n" + "+\t\t\"out %%al,$0x84\\n\\t\"\n" + "+\t\t\"xchgq %%rax,(%%rsp)\\n\\t\"\n" + "+\t\t\"movl %%ebx,4(%%rax)\\n\\t\"\n" + "+\t\t\"movl %%ecx,8(%%rax)\\n\\t\"\n" + "+\t\t\"movl %%edx,12(%%rax)\\n\\t\"\n" + "+\t\t\"movl %%esi,16(%%rax)\\n\\t\"\n" + "+\t\t\"movl %%edi,20(%%rax)\\n\\t\"\n" + "+\t\t\"popq %%rdx\\n\\t\"\n" + "+\t\t\"movl %%edx,0(%%rax)\\n\\t\"\n" + "+\t\t\"pushfq\\n\\t\"\n" + "+\t\t\"popq %%rax\\n\\t\"\n" + "+\t\t\"andl $1,%%eax\\n\"\n" + "+\t\t: \"=a\"(rc)\n" + "+\t\t: \"a\"(regs)\n" + "+\t\t: \"%ebx\", \"%ecx\", \"%edx\", \"%esi\", \"%edi\", \"memory\");\n" + "+#else\n" + "+\tasm volatile(\"pushl %%eax\\n\\t\"\n" + "+\t \"movl 0(%%eax),%%edx\\n\\t\"\n" + "+\t \"push %%edx\\n\\t\"\n" + "+\t \"movl 4(%%eax),%%ebx\\n\\t\"\n" + "+\t \"movl 8(%%eax),%%ecx\\n\\t\"\n" + "+\t \"movl 12(%%eax),%%edx\\n\\t\"\n" + "+\t \"movl 16(%%eax),%%esi\\n\\t\"\n" + "+\t \"movl 20(%%eax),%%edi\\n\\t\"\n" + "+\t \"popl %%eax\\n\\t\"\n" + "+\t \"out %%al,$0xb2\\n\\t\"\n" + "+\t \"out %%al,$0x84\\n\\t\"\n" + "+\t \"xchgl %%eax,(%%esp)\\n\\t\"\n" + "+\t \"movl %%ebx,4(%%eax)\\n\\t\"\n" + "+\t \"movl %%ecx,8(%%eax)\\n\\t\"\n" + "+\t \"movl %%edx,12(%%eax)\\n\\t\"\n" + "+\t \"movl %%esi,16(%%eax)\\n\\t\"\n" + "+\t \"movl %%edi,20(%%eax)\\n\\t\"\n" + "+\t \"popl %%edx\\n\\t\"\n" + "+\t \"movl %%edx,0(%%eax)\\n\\t\"\n" + "+\t \"lahf\\n\\t\"\n" + "+\t \"shrl $8,%%eax\\n\\t\"\n" + "+\t \"andl $1,%%eax\\n\"\n" + "+\t : \"=a\"(rc)\n" + "+\t : \"a\"(regs)\n" + "+\t : \"%ebx\", \"%ecx\", \"%edx\", \"%esi\", \"%edi\", \"memory\");\n" + "+#endif\n" + "+\tif (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)\n" + "+\t\trc = -EINVAL;\n" + "+\n" + "+out:\n" + "+\tset_cpus_allowed_ptr(current, old_mask);\n" + "+\tfree_cpumask_var(old_mask);\n" + "+\treturn rc;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the Fn key status.\n" + "+ */\n" + "+static int i8k_get_fn_status(void)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };\n" + "+\tint rc;\n" + "+\n" + "+\trc = i8k_smm(®s);\n" + "+\tif (rc < 0)\n" + "+\t\treturn rc;\n" + "+\n" + "+\tswitch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {\n" + "+\tcase I8K_FN_UP:\n" + "+\t\treturn I8K_VOL_UP;\n" + "+\tcase I8K_FN_DOWN:\n" + "+\t\treturn I8K_VOL_DOWN;\n" + "+\tcase I8K_FN_MUTE:\n" + "+\t\treturn I8K_VOL_MUTE;\n" + "+\tdefault:\n" + "+\t\treturn 0;\n" + "+\t}\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the power status.\n" + "+ */\n" + "+static int i8k_get_power_status(void)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };\n" + "+\tint rc;\n" + "+\n" + "+\trc = i8k_smm(®s);\n" + "+\tif (rc < 0)\n" + "+\t\treturn rc;\n" + "+\n" + "+\treturn (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the fan status.\n" + "+ */\n" + "+static int i8k_get_fan_status(int fan)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };\n" + "+\n" + "+\tregs.ebx = fan & 0xff;\n" + "+\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the fan speed in RPM.\n" + "+ */\n" + "+static int i8k_get_fan_speed(int fan)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };\n" + "+\n" + "+\tregs.ebx = fan & 0xff;\n" + "+\treturn i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the fan type.\n" + "+ */\n" + "+static int i8k_get_fan_type(int fan)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };\n" + "+\n" + "+\tregs.ebx = fan & 0xff;\n" + "+\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the fan nominal rpm for specific fan speed.\n" + "+ */\n" + "+static int i8k_get_fan_nominal_speed(int fan, int speed)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };\n" + "+\n" + "+\tregs.ebx = (fan & 0xff) | (speed << 8);\n" + "+\treturn i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Set the fan speed (off, low, high). Returns the new fan status.\n" + "+ */\n" + "+static int i8k_set_fan(int fan, int speed)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };\n" + "+\n" + "+\tspeed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);\n" + "+\tregs.ebx = (fan & 0xff) | (speed << 8);\n" + "+\n" + "+\treturn i8k_smm(®s) ? : i8k_get_fan_status(fan);\n" + "+}\n" + "+\n" + "+static int i8k_get_temp_type(int sensor)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };\n" + "+\n" + "+\tregs.ebx = sensor & 0xff;\n" + "+\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Read the cpu temperature.\n" + "+ */\n" + "+static int _i8k_get_temp(int sensor)\n" + "+{\n" + "+\tstruct smm_regs regs = {\n" + "+\t\t.eax = I8K_SMM_GET_TEMP,\n" + "+\t\t.ebx = sensor & 0xff,\n" + "+\t};\n" + "+\n" + "+\treturn i8k_smm(®s) ? : regs.eax & 0xff;\n" + "+}\n" + "+\n" + "+static int i8k_get_temp(int sensor)\n" + "+{\n" + "+\tint temp = _i8k_get_temp(sensor);\n" + "+\n" + "+\t/*\n" + "+\t * Sometimes the temperature sensor returns 0x99, which is out of range.\n" + "+\t * In this case we retry (once) before returning an error.\n" + "+\t # 1003655137 00000058 00005a4b\n" + "+\t # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees\n" + "+\t # 1003655139 00000054 00005c52\n" + "+\t */\n" + "+\tif (temp == 0x99) {\n" + "+\t\tmsleep(100);\n" + "+\t\ttemp = _i8k_get_temp(sensor);\n" + "+\t}\n" + "+\t/*\n" + "+\t * Return -ENODATA for all invalid temperatures.\n" + "+\t *\n" + "+\t * Known instances are the 0x99 value as seen above as well as\n" + "+\t * 0xc1 (193), which may be returned when trying to read the GPU\n" + "+\t * temperature if the system supports a GPU and it is currently\n" + "+\t * turned off.\n" + "+\t */\n" + "+\tif (temp > I8K_MAX_TEMP)\n" + "+\t\treturn -ENODATA;\n" + "+\n" + "+\treturn temp;\n" + "+}\n" + "+\n" + "+static int i8k_get_dell_signature(int req_fn)\n" + "+{\n" + "+\tstruct smm_regs regs = { .eax = req_fn, };\n" + "+\tint rc;\n" + "+\n" + "+\trc = i8k_smm(®s);\n" + "+\tif (rc < 0)\n" + "+\t\treturn rc;\n" + "+\n" + "+\treturn regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;\n" + "+}\n" + "+\n" + "+static int\n" + "+i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)\n" + "+{\n" + "+\tint val = 0;\n" + "+\tint speed;\n" + "+\tunsigned char buff[16];\n" + "+\tint __user *argp = (int __user *)arg;\n" + "+\n" + "+\tif (!argp)\n" + "+\t\treturn -EINVAL;\n" + "+\n" + "+\tswitch (cmd) {\n" + "+\tcase I8K_BIOS_VERSION:\n" + "+\t\tval = (bios_version[0] << 16) |\n" + "+\t\t\t\t(bios_version[1] << 8) | bios_version[2];\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_MACHINE_ID:\n" + "+\t\tmemset(buff, 0, 16);\n" + "+\t\tstrlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),\n" + "+\t\t\tsizeof(buff));\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_FN_STATUS:\n" + "+\t\tval = i8k_get_fn_status();\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_POWER_STATUS:\n" + "+\t\tval = i8k_get_power_status();\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_GET_TEMP:\n" + "+\t\tval = i8k_get_temp(0);\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_GET_SPEED:\n" + "+\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tval = i8k_get_fan_speed(val);\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_GET_FAN:\n" + "+\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tval = i8k_get_fan_status(val);\n" + "+\t\tbreak;\n" + "+\n" + "+\tcase I8K_SET_FAN:\n" + "+\t\tif (restricted && !capable(CAP_SYS_ADMIN))\n" + "+\t\t\treturn -EPERM;\n" + "+\n" + "+\t\tif (copy_from_user(&val, argp, sizeof(int)))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tif (copy_from_user(&speed, argp + 1, sizeof(int)))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tval = i8k_set_fan(val, speed);\n" + "+\t\tbreak;\n" + "+\n" + "+\tdefault:\n" + "+\t\treturn -EINVAL;\n" + "+\t}\n" + "+\n" + "+\tif (val < 0)\n" + "+\t\treturn val;\n" + "+\n" + "+\tswitch (cmd) {\n" + "+\tcase I8K_BIOS_VERSION:\n" + "+\t\tif (copy_to_user(argp, &val, 4))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tbreak;\n" + "+\tcase I8K_MACHINE_ID:\n" + "+\t\tif (copy_to_user(argp, buff, 16))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tbreak;\n" + "+\tdefault:\n" + "+\t\tif (copy_to_user(argp, &val, sizeof(int)))\n" + "+\t\t\treturn -EFAULT;\n" + "+\n" + "+\t\tbreak;\n" + "+\t}\n" + "+\n" + "+\treturn 0;\n" + "+}\n" + "+\n" + "+static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)\n" + "+{\n" + "+\tlong ret;\n" + "+\n" + "+\tmutex_lock(&i8k_mutex);\n" + "+\tret = i8k_ioctl_unlocked(fp, cmd, arg);\n" + "+\tmutex_unlock(&i8k_mutex);\n" + "+\n" + "+\treturn ret;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Print the information for /proc/i8k.\n" + "+ */\n" + "+static int i8k_proc_show(struct seq_file *seq, void *offset)\n" + "+{\n" + "+\tint fn_key, cpu_temp, ac_power;\n" + "+\tint left_fan, right_fan, left_speed, right_speed;\n" + "+\n" + "+\tcpu_temp\t= i8k_get_temp(0);\t\t\t/* 11100 \302\265s */\n" + "+\tleft_fan\t= i8k_get_fan_status(I8K_FAN_LEFT);\t/* 580 \302\265s */\n" + "+\tright_fan\t= i8k_get_fan_status(I8K_FAN_RIGHT);\t/* 580 \302\265s */\n" + "+\tleft_speed\t= i8k_get_fan_speed(I8K_FAN_LEFT);\t/* 580 \302\265s */\n" + "+\tright_speed\t= i8k_get_fan_speed(I8K_FAN_RIGHT);\t/* 580 \302\265s */\n" + "+\tfn_key\t\t= i8k_get_fn_status();\t\t\t/* 750 \302\265s */\n" + "+\tif (power_status)\n" + "+\t\tac_power = i8k_get_power_status();\t\t/* 14700 \302\265s */\n" + "+\telse\n" + "+\t\tac_power = -1;\n" + "+\n" + "+\t/*\n" + "+\t * Info:\n" + "+\t *\n" + "+\t * 1) Format version (this will change if format changes)\n" + "+\t * 2) BIOS version\n" + "+\t * 3) BIOS machine ID\n" + "+\t * 4) Cpu temperature\n" + "+\t * 5) Left fan status\n" + "+\t * 6) Right fan status\n" + "+\t * 7) Left fan speed\n" + "+\t * 8) Right fan speed\n" + "+\t * 9) AC power\n" + "+\t * 10) Fn Key status\n" + "+\t */\n" + "+\treturn seq_printf(seq, \"%s %s %s %d %d %d %d %d %d %d\\n\",\n" + "+\t\t\t I8K_PROC_FMT,\n" + "+\t\t\t bios_version,\n" + "+\t\t\t i8k_get_dmi_data(DMI_PRODUCT_SERIAL),\n" + "+\t\t\t cpu_temp,\n" + "+\t\t\t left_fan, right_fan, left_speed, right_speed,\n" + "+\t\t\t ac_power, fn_key);\n" + "+}\n" + "+\n" + "+static int i8k_open_fs(struct inode *inode, struct file *file)\n" + "+{\n" + "+\treturn single_open(file, i8k_proc_show, NULL);\n" + "+}\n" + "+\n" + "+\n" + "+/*\n" + "+ * Hwmon interface\n" + "+ */\n" + "+\n" + "+static ssize_t i8k_hwmon_show_temp_label(struct device *dev,\n" + "+\t\t\t\t\t struct device_attribute *devattr,\n" + "+\t\t\t\t\t char *buf)\n" + "+{\n" + "+\tstatic const char * const labels[] = {\n" + "+\t\t\"CPU\",\n" + "+\t\t\"GPU\",\n" + "+\t\t\"SODIMM\",\n" + "+\t\t\"Other\",\n" + "+\t\t\"Ambient\",\n" + "+\t\t\"Other\",\n" + "+\t};\n" + "+\tint index = to_sensor_dev_attr(devattr)->index;\n" + "+\tint type;\n" + "+\n" + "+\ttype = i8k_get_temp_type(index);\n" + "+\tif (type < 0)\n" + "+\t\treturn type;\n" + "+\tif (type >= ARRAY_SIZE(labels))\n" + "+\t\ttype = ARRAY_SIZE(labels) - 1;\n" + "+\treturn sprintf(buf, \"%s\\n\", labels[type]);\n" + "+}\n" + "+\n" + "+static ssize_t i8k_hwmon_show_temp(struct device *dev,\n" + "+\t\t\t\t struct device_attribute *devattr,\n" + "+\t\t\t\t char *buf)\n" + "+{\n" + "+\tint index = to_sensor_dev_attr(devattr)->index;\n" + "+\tint temp;\n" + "+\n" + "+\ttemp = i8k_get_temp(index);\n" + "+\tif (temp < 0)\n" + "+\t\treturn temp;\n" + "+\treturn sprintf(buf, \"%d\\n\", temp * 1000);\n" + "+}\n" + "+\n" + "+static ssize_t i8k_hwmon_show_fan_label(struct device *dev,\n" + "+\t\t\t\t\tstruct device_attribute *devattr,\n" + "+\t\t\t\t\tchar *buf)\n" + "+{\n" + "+\tstatic const char * const labels[] = {\n" + "+\t\t\"Processor Fan\",\n" + "+\t\t\"Motherboard Fan\",\n" + "+\t\t\"Video Fan\",\n" + "+\t\t\"Power Supply Fan\",\n" + "+\t\t\"Chipset Fan\",\n" + "+\t\t\"Other Fan\",\n" + "+\t};\n" + "+\tint index = to_sensor_dev_attr(devattr)->index;\n" + "+\tbool dock = false;\n" + "+\tint type;\n" + "+\n" + "+\ttype = i8k_get_fan_type(index);\n" + "+\tif (type < 0)\n" + "+\t\treturn type;\n" + "+\n" + "+\tif (type & 0x10) {\n" + "+\t\tdock = true;\n" + "+\t\ttype &= 0x0F;\n" + "+\t}\n" + "+\n" + "+\tif (type >= ARRAY_SIZE(labels))\n" + "+\t\ttype = (ARRAY_SIZE(labels) - 1);\n" + "+\n" + "+\treturn sprintf(buf, \"%s%s\\n\", (dock ? \"Docking \" : \"\"), labels[type]);\n" + "+}\n" + "+\n" + "+static ssize_t i8k_hwmon_show_fan(struct device *dev,\n" + "+\t\t\t\t struct device_attribute *devattr,\n" + "+\t\t\t\t char *buf)\n" + "+{\n" + "+\tint index = to_sensor_dev_attr(devattr)->index;\n" + "+\tint fan_speed;\n" + "+\n" + "+\tfan_speed = i8k_get_fan_speed(index);\n" + "+\tif (fan_speed < 0)\n" + "+\t\treturn fan_speed;\n" + "+\treturn sprintf(buf, \"%d\\n\", fan_speed);\n" + "+}\n" + "+\n" + "+static ssize_t i8k_hwmon_show_pwm(struct device *dev,\n" + "+\t\t\t\t struct device_attribute *devattr,\n" + "+\t\t\t\t char *buf)\n" + "+{\n" + "+\tint index = to_sensor_dev_attr(devattr)->index;\n" + "+\tint status;\n" + "+\n" + "+\tstatus = i8k_get_fan_status(index);\n" + "+\tif (status < 0)\n" + "+\t\treturn -EIO;\n" + "+\treturn sprintf(buf, \"%d\\n\", clamp_val(status * i8k_pwm_mult, 0, 255));\n" + "+}\n" + "+\n" + "+static ssize_t i8k_hwmon_set_pwm(struct device *dev,\n" + "+\t\t\t\t struct device_attribute *attr,\n" + "+\t\t\t\t const char *buf, size_t count)\n" + "+{\n" + "+\tint index = to_sensor_dev_attr(attr)->index;\n" + "+\tunsigned long val;\n" + "+\tint err;\n" + "+\n" + "+\terr = kstrtoul(buf, 10, &val);\n" + "+\tif (err)\n" + "+\t\treturn err;\n" + "+\tval = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);\n" + "+\n" + "+\tmutex_lock(&i8k_mutex);\n" + "+\terr = i8k_set_fan(index, val);\n" + "+\tmutex_unlock(&i8k_mutex);\n" + "+\n" + "+\treturn err < 0 ? -EIO : count;\n" + "+}\n" + "+\n" + "+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);\n" + "+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "+\t\t\t 0);\n" + "+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);\n" + "+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "+\t\t\t 1);\n" + "+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);\n" + "+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "+\t\t\t 2);\n" + "+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);\n" + "+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,\n" + "+\t\t\t 3);\n" + "+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);\n" + "+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,\n" + "+\t\t\t 0);\n" + "+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,\n" + "+\t\t\t i8k_hwmon_set_pwm, 0);\n" + "+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,\n" + "+\t\t\t 1);\n" + "+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,\n" + "+\t\t\t 1);\n" + "+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,\n" + "+\t\t\t i8k_hwmon_set_pwm, 1);\n" + "+\n" + "+static struct attribute *i8k_attrs[] = {\n" + "+\t&sensor_dev_attr_temp1_input.dev_attr.attr,\t/* 0 */\n" + "+\t&sensor_dev_attr_temp1_label.dev_attr.attr,\t/* 1 */\n" + "+\t&sensor_dev_attr_temp2_input.dev_attr.attr,\t/* 2 */\n" + "+\t&sensor_dev_attr_temp2_label.dev_attr.attr,\t/* 3 */\n" + "+\t&sensor_dev_attr_temp3_input.dev_attr.attr,\t/* 4 */\n" + "+\t&sensor_dev_attr_temp3_label.dev_attr.attr,\t/* 5 */\n" + "+\t&sensor_dev_attr_temp4_input.dev_attr.attr,\t/* 6 */\n" + "+\t&sensor_dev_attr_temp4_label.dev_attr.attr,\t/* 7 */\n" + "+\t&sensor_dev_attr_fan1_input.dev_attr.attr,\t/* 8 */\n" + "+\t&sensor_dev_attr_fan1_label.dev_attr.attr,\t/* 9 */\n" + "+\t&sensor_dev_attr_pwm1.dev_attr.attr,\t\t/* 10 */\n" + "+\t&sensor_dev_attr_fan2_input.dev_attr.attr,\t/* 11 */\n" + "+\t&sensor_dev_attr_fan2_label.dev_attr.attr,\t/* 12 */\n" + "+\t&sensor_dev_attr_pwm2.dev_attr.attr,\t\t/* 13 */\n" + "+\tNULL\n" + "+};\n" + "+\n" + "+static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,\n" + "+\t\t\t int index)\n" + "+{\n" + "+\tif (index >= 0 && index <= 1 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))\n" + "+\t\treturn 0;\n" + "+\tif (index >= 2 && index <= 3 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))\n" + "+\t\treturn 0;\n" + "+\tif (index >= 4 && index <= 5 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))\n" + "+\t\treturn 0;\n" + "+\tif (index >= 6 && index <= 7 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))\n" + "+\t\treturn 0;\n" + "+\tif (index >= 8 && index <= 10 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))\n" + "+\t\treturn 0;\n" + "+\tif (index >= 11 && index <= 13 &&\n" + "+\t !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))\n" + "+\t\treturn 0;\n" + "+\n" + "+\treturn attr->mode;\n" + "+}\n" + "+\n" + "+static const struct attribute_group i8k_group = {\n" + "+\t.attrs = i8k_attrs,\n" + "+\t.is_visible = i8k_is_visible,\n" + "+};\n" + "+__ATTRIBUTE_GROUPS(i8k);\n" + "+\n" + "+static int __init i8k_init_hwmon(void)\n" + "+{\n" + "+\tint err;\n" + "+\n" + "+\ti8k_hwmon_flags = 0;\n" + "+\n" + "+\t/* CPU temperature attributes, if temperature type is OK */\n" + "+\terr = i8k_get_temp_type(0);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;\n" + "+\t/* check for additional temperature sensors */\n" + "+\terr = i8k_get_temp_type(1);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;\n" + "+\terr = i8k_get_temp_type(2);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;\n" + "+\terr = i8k_get_temp_type(3);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;\n" + "+\n" + "+\t/* First fan attributes, if fan type is OK */\n" + "+\terr = i8k_get_fan_type(0);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;\n" + "+\n" + "+\t/* Second fan attributes, if fan type is OK */\n" + "+\terr = i8k_get_fan_type(1);\n" + "+\tif (err >= 0)\n" + "+\t\ti8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;\n" + "+\n" + "+\ti8k_hwmon_dev = hwmon_device_register_with_groups(NULL, \"i8k\", NULL,\n" + "+\t\t\t\t\t\t\t i8k_groups);\n" + "+\tif (IS_ERR(i8k_hwmon_dev)) {\n" + "+\t\terr = PTR_ERR(i8k_hwmon_dev);\n" + "+\t\ti8k_hwmon_dev = NULL;\n" + "+\t\tpr_err(\"hwmon registration failed (%d)\\n\", err);\n" + "+\t\treturn err;\n" + "+\t}\n" + "+\treturn 0;\n" + "+}\n" + "+\n" + "+struct i8k_config_data {\n" + "+\tuint fan_mult;\n" + "+\tuint fan_max;\n" + "+};\n" + "+\n" + "+enum i8k_configs {\n" + "+\tDELL_LATITUDE_D520,\n" + "+\tDELL_PRECISION_490,\n" + "+\tDELL_STUDIO,\n" + "+\tDELL_XPS,\n" + "+};\n" + "+\n" + "+static const struct i8k_config_data i8k_config_data[] = {\n" + "+\t[DELL_LATITUDE_D520] = {\n" + "+\t\t.fan_mult = 1,\n" + "+\t\t.fan_max = I8K_FAN_TURBO,\n" + "+\t},\n" + "+\t[DELL_PRECISION_490] = {\n" + "+\t\t.fan_mult = 1,\n" + "+\t\t.fan_max = I8K_FAN_TURBO,\n" + "+\t},\n" + "+\t[DELL_STUDIO] = {\n" + "+\t\t.fan_mult = 1,\n" + "+\t\t.fan_max = I8K_FAN_HIGH,\n" + "+\t},\n" + "+\t[DELL_XPS] = {\n" + "+\t\t.fan_mult = 1,\n" + "+\t\t.fan_max = I8K_FAN_HIGH,\n" + "+\t},\n" + "+};\n" + "+\n" + "+static struct dmi_system_id i8k_dmi_table[] __initdata = {\n" + "+\t{\n" + "+\t\t.ident = \"Dell Inspiron\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Computer\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Inspiron\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Latitude\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Computer\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Inspiron 2\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Inspiron\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Latitude D520\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude D520\"),\n" + "+\t\t},\n" + "+\t\t.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Latitude 2\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Latitude\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\t/* UK Inspiron 6400 */\n" + "+\t\t.ident = \"Dell Inspiron 3\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MM061\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Inspiron 3\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MP061\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Precision 490\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME,\n" + "+\t\t\t\t \"Precision WorkStation 490\"),\n" + "+\t\t},\n" + "+\t\t.driver_data = (void *)&i8k_config_data[DELL_PRECISION_490],\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Precision\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Precision\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Vostro\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Vostro\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell XPS421\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"XPS L421X\"),\n" + "+\t\t},\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell Studio\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"Studio\"),\n" + "+\t\t},\n" + "+\t\t.driver_data = (void *)&i8k_config_data[DELL_STUDIO],\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell XPS 13\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"XPS13\"),\n" + "+\t\t},\n" + "+\t\t.driver_data = (void *)&i8k_config_data[DELL_XPS],\n" + "+\t},\n" + "+\t{\n" + "+\t\t.ident = \"Dell XPS M140\",\n" + "+\t\t.matches = {\n" + "+\t\t\tDMI_MATCH(DMI_SYS_VENDOR, \"Dell Inc.\"),\n" + "+\t\t\tDMI_MATCH(DMI_PRODUCT_NAME, \"MXC051\"),\n" + "+\t\t},\n" + "+\t\t.driver_data = (void *)&i8k_config_data[DELL_XPS],\n" + "+\t},\n" + "+\t{ }\n" + "+};\n" + "+\n" + "+MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);\n" + "+\n" + "+/*\n" + "+ * Probe for the presence of a supported laptop.\n" + "+ */\n" + "+static int __init i8k_probe(void)\n" + "+{\n" + "+\tconst struct dmi_system_id *id;\n" + "+\tint fan, ret;\n" + "+\n" + "+\t/*\n" + "+\t * Get DMI information\n" + "+\t */\n" + "+\tif (!dmi_check_system(i8k_dmi_table)) {\n" + "+\t\tif (!ignore_dmi && !force)\n" + "+\t\t\treturn -ENODEV;\n" + "+\n" + "+\t\tpr_info(\"not running on a supported Dell system.\\n\");\n" + "+\t\tpr_info(\"vendor=%s, model=%s, version=%s\\n\",\n" + "+\t\t\ti8k_get_dmi_data(DMI_SYS_VENDOR),\n" + "+\t\t\ti8k_get_dmi_data(DMI_PRODUCT_NAME),\n" + "+\t\t\ti8k_get_dmi_data(DMI_BIOS_VERSION));\n" + "+\t}\n" + "+\n" + "+\tstrlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),\n" + "+\t\tsizeof(bios_version));\n" + "+\n" + "+\t/*\n" + "+\t * Get SMM Dell signature\n" + "+\t */\n" + "+\tif (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&\n" + "+\t i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {\n" + "+\t\tpr_err(\"unable to get SMM Dell signature\\n\");\n" + "+\t\tif (!force)\n" + "+\t\t\treturn -ENODEV;\n" + "+\t}\n" + "+\n" + "+\t/*\n" + "+\t * Set fan multiplier and maximal fan speed from dmi config\n" + "+\t * Values specified in module parameters override values from dmi\n" + "+\t */\n" + "+\tid = dmi_first_match(i8k_dmi_table);\n" + "+\tif (id && id->driver_data) {\n" + "+\t\tconst struct i8k_config_data *conf = id->driver_data;\n" + "+\t\tif (!fan_mult && conf->fan_mult)\n" + "+\t\t\tfan_mult = conf->fan_mult;\n" + "+\t\tif (!fan_max && conf->fan_max)\n" + "+\t\t\tfan_max = conf->fan_max;\n" + "+\t}\n" + "+\n" + "+\ti8k_fan_max = fan_max ? : I8K_FAN_HIGH;\t/* Must not be 0 */\n" + "+\ti8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);\n" + "+\n" + "+\tif (!fan_mult) {\n" + "+\t\t/*\n" + "+\t\t * Autodetect fan multiplier based on nominal rpm\n" + "+\t\t * If fan reports rpm value too high then set multiplier to 1\n" + "+\t\t */\n" + "+\t\tfor (fan = 0; fan < 2; ++fan) {\n" + "+\t\t\tret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);\n" + "+\t\t\tif (ret < 0)\n" + "+\t\t\t\tcontinue;\n" + "+\t\t\tif (ret > I8K_FAN_MAX_RPM)\n" + "+\t\t\t\ti8k_fan_mult = 1;\n" + "+\t\t\tbreak;\n" + "+\t\t}\n" + "+\t} else {\n" + "+\t\t/* Fan multiplier was specified in module param or in dmi */\n" + "+\t\ti8k_fan_mult = fan_mult;\n" + "+\t}\n" + "+\n" + "+\treturn 0;\n" + "+}\n" + "+\n" + "+static int __init i8k_init(void)\n" + "+{\n" + "+\tstruct proc_dir_entry *proc_i8k;\n" + "+\tint err;\n" + "+\n" + "+\t/* Are we running on an supported laptop? */\n" + "+\tif (i8k_probe())\n" + "+\t\treturn -ENODEV;\n" + "+\n" + "+\t/* Register the proc entry */\n" + "+\tproc_i8k = proc_create(\"i8k\", 0, NULL, &i8k_fops);\n" + "+\tif (!proc_i8k)\n" + "+\t\treturn -ENOENT;\n" + "+\n" + "+\terr = i8k_init_hwmon();\n" + "+\tif (err)\n" + "+\t\tgoto exit_remove_proc;\n" + "+\n" + "+\treturn 0;\n" + "+\n" + "+ exit_remove_proc:\n" + "+\tremove_proc_entry(\"i8k\", NULL);\n" + "+\treturn err;\n" + "+}\n" + "+\n" + "+static void __exit i8k_exit(void)\n" + "+{\n" + "+\thwmon_device_unregister(i8k_hwmon_dev);\n" + "+\tremove_proc_entry(\"i8k\", NULL);\n" + "+}\n" + "+\n" + "+module_init(i8k_init);\n" + "+module_exit(i8k_exit);\n" + "-- \n" + 1.7.9.5 -19f91de87c929a4c3d42fe6dbd83f3420bfb75e4ea1859e8ada7cbeba06c04a7 +3399d7ff90d35b97828b6dbb0a78706c83ef15cc7cfa95d2a99f023fb273644a
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.