LyoKICogU3VwcG9ydCBmb3IgZW11bGF0aW5nIFNBVCAoYXRhIHBhc3MgdGhyb3VnaCkgb24gZGV2aWNlcyBiYXNlZAogKiAgICAgICBvbiB0aGUgQ3lwcmVzcyBVU0IvQVRBIGJyaWRnZSBzdXBwb3J0aW5nIEFUQUNCLgogKgogKiBDb3B5cmlnaHQgKGMpIDIwMDggTWF0dGhpZXUgQ2FzdGV0IChjYXN0ZXQubWF0dGhpZXVAZnJlZS5mcikKICoKICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQKICogdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlCiAqIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMiwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkKICogbGF0ZXIgdmVyc2lvbi4KICoKICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dAogKiBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VCiAqIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KICoKICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcKICogd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKICogNjc1IE1hc3MgQXZlLCBDYW1icmlkZ2UsIE1BIDAyMTM5LCBVU0EuCiAqLwoKI2luY2x1ZGUgPHNjc2kvc2NzaS5oPgojaW5jbHVkZSA8c2NzaS9zY3NpX2NtbmQuaD4KI2luY2x1ZGUgPHNjc2kvc2NzaV9laC5oPgojaW5jbHVkZSA8bGludXgvYXRhLmg+CgojaW5jbHVkZSAidXNiLmgiCiNpbmNsdWRlICJwcm90b2NvbC5oIgojaW5jbHVkZSAic2NzaWdsdWUuaCIKI2luY2x1ZGUgImRlYnVnLmgiCgovKgogKiBBVEFDQiBpcyBhIHByb3RvY29sIHVzZWQgb24gY3lwcmVzcyB1c2I8LT5hdGEgYnJpZGdlIHRvCiAqIHNlbmQgcmF3IEFUQSBjb21tYW5kIG92ZXIgbWFzcyBzdG9yYWdlCiAqIFRoZXJlIGlzIGEgQVRBQ0IyIHByb3RvY29sIHRoYXQgc3VwcG9ydCBMQkE0OCBvbiBuZXdlciBjaGlwLgogKiBNb3JlIGluZm8gdGhhdCBiZSBmb3VuZCBvbiBjeTdjNjgzMTBfOC5wZGYgYW5kIGN5N2M2ODMwMGNfOC5wZGYKICogZGF0YXNoZWV0IGZyb20gY3lwcmVzcy5jb20uCiAqLwp2b2lkIGN5cHJlc3NfYXRhY2JfcGFzc3Rocm91Z2goc3RydWN0IHNjc2lfY21uZCAqc3JiLCBzdHJ1Y3QgdXNfZGF0YSAqdXMpCnsKCXVuc2lnbmVkIGNoYXIgc2F2ZV9jbW5kW01BWF9DT01NQU5EX1NJWkVdOwoKCWlmIChsaWtlbHkoc3JiLT5jbW5kWzBdICE9IEFUQV8xNiAmJiBzcmItPmNtbmRbMF0gIT0gQVRBXzEyKSkgewoJCXVzYl9zdG9yX3RyYW5zcGFyZW50X3Njc2lfY29tbWFuZChzcmIsIHVzKTsKCQlyZXR1cm47Cgl9CgoJbWVtY3B5KHNhdmVfY21uZCwgc3JiLT5jbW5kLCBzaXplb2Yoc2F2ZV9jbW5kKSk7CgltZW1zZXQoc3JiLT5jbW5kLCAwLCBNQVhfQ09NTUFORF9TSVpFKTsKCgkvKiBjaGVjayBpZiB3ZSBzdXBwb3J0IHRoZSBjb21tYW5kICovCglpZiAoc2F2ZV9jbW5kWzFdID4+IDUpIC8qIE1VTFRJUExFX0NPVU5UICovCgkJZ290byBpbnZhbGlkX2ZsZDsKCS8qIGNoZWNrIHByb3RvY29sICovCglzd2l0Y2goKHNhdmVfY21uZFsxXSA+PiAxKSAmIDB4ZikgewoJCWNhc2UgMzogLypubyBEQVRBICovCgkJY2FzZSA0OiAvKiBQSU8gaW4gKi8KCQljYXNlIDU6IC8qIFBJTyBvdXQgKi8KCQkJYnJlYWs7CgkJZGVmYXVsdDoKCQkJZ290byBpbnZhbGlkX2ZsZDsKCX0KCgkvKiBmaXJzdCBidWlsZCB0aGUgQVRBQ0IgY29tbWFuZCAqLwoJc3JiLT5jbWRfbGVuID0gMTY7CgoJc3JiLT5jbW5kWzBdID0gMHgyNDsgLyogYlZTQ0JTaWduYXR1cmUgOiB2ZW5kb3Itc3BlY2lmaWMgY29tbWFuZAoJICAgICAgICAgICAgICAgICAgICAgICAgdGhpcyB2YWx1ZSBjYW4gY2hhbmdlLCBidXQgbW9zdChhbGwgPykgbWFudWZhY3R1cmVycwoJCQkJCQkJa2VlcCB0aGUgY3lwcmVzcyBkZWZhdWx0IDogMHgyNCAqLwoJc3JiLT5jbW5kWzFdID0gMHgyNDsgLyogYlZTQ0JTdWJDb21tYW5kIDogMHgyNCBmb3IgQVRBQ0IgKi8KCglzcmItPmNtbmRbM10gPSAweGZmIC0gMTsgLyogZmVhdHVyZXMsIHNlY3RvciBjb3VudCwgbGJhIGxvdywgbGJhIG1lZAoJCQkJCQkJCWxiYSBoaWdoLCBkZXZpY2UsIGNvbW1hbmQgYXJlIHZhbGlkICovCglzcmItPmNtbmRbNF0gPSAxOyAvKiBUcmFuc2ZlckJsb2NrQ291bnQgOiA1MTIgKi8KCglpZiAoc2F2ZV9jbW5kWzBdID09IEFUQV8xNikgewoJCXNyYi0+Y21uZFsgNl0gPSBzYXZlX2NtbmRbIDRdOyAvKiBmZWF0dXJlcyAqLwoJCXNyYi0+Y21uZFsgN10gPSBzYXZlX2NtbmRbIDZdOyAvKiBzZWN0b3IgY291bnQgKi8KCQlzcmItPmNtbmRbIDhdID0gc2F2ZV9jbW5kWyA4XTsgLyogbGJhIGxvdyAqLwoJCXNyYi0+Y21uZFsgOV0gPSBzYXZlX2NtbmRbMTBdOyAvKiBsYmEgbWVkICovCgkJc3JiLT5jbW5kWzEwXSA9IHNhdmVfY21uZFsxMl07IC8qIGxiYSBoaWdoICovCgkJc3JiLT5jbW5kWzExXSA9IHNhdmVfY21uZFsxM107IC8qIGRldmljZSAqLwoJCXNyYi0+Y21uZFsxMl0gPSBzYXZlX2NtbmRbMTRdOyAvKiBjb21tYW5kICovCgoJCWlmIChzYXZlX2NtbmRbMV0gJiAweDAxKSB7LyogZXh0ZW5kZWQgYml0IHNldCBmb3IgTEJBNDggKi8KCQkJLyogdGhpcyBjb3VsZCBiZSBzdXBwb3J0ZWQgYnkgYXRhY2IyICovCgkJCWlmIChzYXZlX2NtbmRbM10gfHwgc2F2ZV9jbW5kWzVdIHx8IHNhdmVfY21uZFs3XSB8fCBzYXZlX2NtbmRbOV0KCQkJCQl8fCBzYXZlX2NtbmRbMTFdKQoJCQkJZ290byBpbnZhbGlkX2ZsZDsKCQl9Cgl9CgllbHNlIHsgLyogQVRBMTIgKi8KCQlzcmItPmNtbmRbIDZdID0gc2F2ZV9jbW5kWzNdOyAvKiBmZWF0dXJlcyAqLwoJCXNyYi0+Y21uZFsgN10gPSBzYXZlX2NtbmRbNF07IC8qIHNlY3RvciBjb3VudCAqLwoJCXNyYi0+Y21uZFsgOF0gPSBzYXZlX2NtbmRbNV07IC8qIGxiYSBsb3cgKi8KCQlzcmItPmNtbmRbIDldID0gc2F2ZV9jbW5kWzZdOyAvKiBsYmEgbWVkICovCgkJc3JiLT5jbW5kWzEwXSA9IHNhdmVfY21uZFs3XTsgLyogbGJhIGhpZ2ggKi8KCQlzcmItPmNtbmRbMTFdID0gc2F2ZV9jbW5kWzhdOyAvKiBkZXZpY2UgKi8KCQlzcmItPmNtbmRbMTJdID0gc2F2ZV9jbW5kWzldOyAvKiBjb21tYW5kICovCgoJfQoJLyogRmlsdGVyIFNFVF9GRUFUVVJFUyAtIFhGRVIgTU9ERSBjb21tYW5kICovCglpZiAoKHNyYi0+Y21uZFsxMl0gPT0gQVRBX0NNRF9TRVRfRkVBVFVSRVMpCgkJCSYmIChzcmItPmNtbmRbNl0gPT0gU0VURkVBVFVSRVNfWEZFUikpCgkJZ290byBpbnZhbGlkX2ZsZDsKCglpZiAoc3JiLT5jbW5kWzEyXSA9PSBBVEFfQ01EX0lEX0FUQSB8fCBzcmItPmNtbmRbMTJdID09IEFUQV9DTURfSURfQVRBUEkpCgkJc3JiLT5jbW5kWzJdIHw9ICgxPDw3KTsgLyogc2V0ICBJZGVudGlmeVBhY2tldERldmljZSBmb3IgdGhlc2UgY21kcyAqLwoKCgl1c2Jfc3Rvcl90cmFuc3BhcmVudF9zY3NpX2NvbW1hbmQoc3JiLCB1cyk7CgoJLyogaWYgdGhlIGRldmljZSBkb2Vzbid0IHN1cHBvcnQgQVRBQ0IKCSAqLwoJaWYgKHNyYi0+cmVzdWx0ID09IFNBTV9TVEFUX0NIRUNLX0NPTkRJVElPTiAmJgoJCQltZW1jbXAoc3JiLT5zZW5zZV9idWZmZXIsIHVzYl9zdG9yX3NlbnNlX2ludmFsaWRDREIsCgkJCQlzaXplb2YodXNiX3N0b3Jfc2Vuc2VfaW52YWxpZENEQikpID09IDApIHsKCQlVU19ERUJVR1AoImN5cHJlc3MgYXRhY2Igbm90IHN1cHBvcnRlZCA/Pz9cbiIpOwoJCWdvdG8gZW5kOwoJfQoKCS8qIGlmIGNrX2NvbmQgZmxhZ3MgaXMgc2V0LCBhbmQgdGhlcmUgd2Fzbid0IGNyaXRpY2FsIGVycm9yLAoJICogYnVpbGQgdGhlIHNwZWNpYWwgc2Vuc2UKCSAqLwoJaWYgKChzcmItPnJlc3VsdCAhPSAoRElEX0VSUk9SIDw8IDE2KSAmJgoJCQkJc3JiLT5yZXN1bHQgIT0gKERJRF9BQk9SVCA8PCAxNikpICYmCgkJCXNhdmVfY21uZFsyXSAmIDB4MjApIHsKCQlzdHJ1Y3Qgc2NzaV9laF9zYXZlIHNlczsKCQl1bnNpZ25lZCBjaGFyIHJlZ3NbOF07CgkJdW5zaWduZWQgY2hhciAqc2IgPSBzcmItPnNlbnNlX2J1ZmZlcjsKCQl1bnNpZ25lZCBjaGFyICpkZXNjID0gc2IgKyA4OwoJCWludCB0bXBfcmVzdWx0OwoKCQkvKiBidWlsZCB0aGUgY29tbWFuZCBmb3IKCQkgKiByZWFkaW5nIHRoZSBBVEEgcmVnaXN0ZXJzICovCgkJc2NzaV9laF9wcmVwX2NtbmQoc3JiLCAmc2VzLCBOVUxMLCAwLCAwKTsKCQlzcmItPnNkYi5sZW5ndGggPSBzaXplb2YocmVncyk7CgkJc2dfaW5pdF9vbmUoJnNlcy5zZW5zZV9zZ2wsIHJlZ3MsIHNyYi0+c2RiLmxlbmd0aCk7CgkJc3JiLT5zZGIudGFibGUuc2dsID0gJnNlcy5zZW5zZV9zZ2w7CgkJc3JiLT5zY19kYXRhX2RpcmVjdGlvbiA9IERNQV9GUk9NX0RFVklDRTsKCQlzcmItPnNkYi50YWJsZS5uZW50cyA9IDE7CgkJLyogd2UgdXNlIHRoZSBzYW1lIGNvbW1hbmQgYXMgYmVmb3JlLCBidXQgd2Ugc2V0CgkJICogdGhlIHJlYWQgdGFza2ZpbGUgYml0LCBmb3Igbm90IGV4ZWN1dGluZyBhdGFjYiBjb21tYW5kLAoJCSAqIGJ1dCByZWFkaW5nIHJlZ2lzdGVyIHNlbGVjdGVkIGluIHNyYi0+Y21uZFs0XQoJCSAqLwoJCXNyYi0+Y21uZFsyXSA9IDE7CgoJCXVzYl9zdG9yX3RyYW5zcGFyZW50X3Njc2lfY29tbWFuZChzcmIsIHVzKTsKCQl0bXBfcmVzdWx0ID0gc3JiLT5yZXN1bHQ7CgkJc2NzaV9laF9yZXN0b3JlX2NtbmQoc3JiLCAmc2VzKTsKCQkvKiB3ZSBmYWlsIHRvIGdldCByZWdpc3RlcnMsIHJlcG9ydCBpbnZhbGlkIGNvbW1hbmQgKi8KCQlpZiAodG1wX3Jlc3VsdCAhPSBTQU1fU1RBVF9HT09EKQoJCQlnb3RvIGludmFsaWRfZmxkOwoKCQkvKiBidWlsZCB0aGUgc2Vuc2UgKi8KCQltZW1zZXQoc2IsIDAsIFNDU0lfU0VOU0VfQlVGRkVSU0laRSk7CgoJCS8qIHNldCBzaywgYXNjIGZvciBhIGdvb2QgY29tbWFuZCAqLwoJCXNiWzFdID0gUkVDT1ZFUkVEX0VSUk9SOwoJCXNiWzJdID0gMDsgLyogQVRBIFBBU1MgVEhST1VHSCBJTkZPUk1BVElPTiBBVkFJTEFCTEUgKi8KCQlzYlszXSA9IDB4MUQ7CgoJCS8qIFhYWCB3ZSBzaG91bGQgZ2VuZXJhdGUgc2ssIGFzYywgYXNjcSBmcm9tIHN0YXR1cyBhbmQgZXJyb3IKCQkgKiByZWdzCgkJICogKHNlZSAxMS4xIEVycm9yIHRyYW5zbGF0aW9uIK0gQVRBIGRldmljZSBlcnJvciB0byBTQ1NJIGVycm9yIG1hcCkKCQkgKiBhbmQgYXRhX3RvX3NlbnNlX2Vycm9yIGZyb20gbGliYXRhLgoJCSAqLwoKCQkvKiBTZW5zZSBkYXRhIGlzIGN1cnJlbnQgYW5kIGZvcm1hdCBpcyBkZXNjcmlwdG9yLiAqLwoJCXNiWzBdID0gMHg3MjsKCQlkZXNjWzBdID0gMHgwOTsgLyogQVRBX1JFVFVSTl9ERVNDUklQVE9SICovCgoJCS8qIHNldCBsZW5ndGggb2YgYWRkaXRpb25hbCBzZW5zZSBkYXRhICovCgkJc2JbN10gPSAxNDsKCQlkZXNjWzFdID0gMTI7CgoJCS8qIENvcHkgcmVnaXN0ZXJzIGludG8gc2Vuc2UgYnVmZmVyLiAqLwoJCWRlc2NbIDJdID0gMHgwMDsKCQlkZXNjWyAzXSA9IHJlZ3NbMV07ICAvKiBmZWF0dXJlcyAqLwoJCWRlc2NbIDVdID0gcmVnc1syXTsgIC8qIHNlY3RvciBjb3VudCAqLwoJCWRlc2NbIDddID0gcmVnc1szXTsgIC8qIGxiYSBsb3cgKi8KCQlkZXNjWyA5XSA9IHJlZ3NbNF07ICAvKiBsYmEgbWVkICovCgkJZGVzY1sxMV0gPSByZWdzWzVdOyAgLyogbGJhIGhpZ2ggKi8KCQlkZXNjWzEyXSA9IHJlZ3NbNl07ICAvKiBkZXZpY2UgKi8KCQlkZXNjWzEzXSA9IHJlZ3NbN107ICAvKiBjb21tYW5kICovCgoJCXNyYi0+cmVzdWx0ID0gKERSSVZFUl9TRU5TRSA8PCAyNCkgfCBTQU1fU1RBVF9DSEVDS19DT05ESVRJT047Cgl9Cglnb3RvIGVuZDsKaW52YWxpZF9mbGQ6CglzcmItPnJlc3VsdCA9IChEUklWRVJfU0VOU0UgPDwgMjQpIHwgU0FNX1NUQVRfQ0hFQ0tfQ09ORElUSU9OOwoKCW1lbWNweShzcmItPnNlbnNlX2J1ZmZlciwKCQkJdXNiX3N0b3Jfc2Vuc2VfaW52YWxpZENEQiwKCQkJc2l6ZW9mKHVzYl9zdG9yX3NlbnNlX2ludmFsaWRDREIpKTsKZW5kOgoJbWVtY3B5KHNyYi0+Y21uZCwgc2F2ZV9jbW5kLCBzaXplb2Yoc2F2ZV9jbW5kKSk7CglpZiAoc3JiLT5jbW5kWzBdID09IEFUQV8xMikKCQlzcmItPmNtZF9sZW4gPSAxMjsKfQo=