From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [RFC,v2,09/15] usb:cdns3: EpX operations part of the API From: Roger Quadros Message-Id: <5BFE8E12.9080307@ti.com> Date: Wed, 28 Nov 2018 14:46:10 +0200 To: Pawel Laszczak , devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com List-ID: T24gMTgvMTEvMTggMTI6MDksIFBhd2VsIExhc3pjemFrIHdyb3RlOgo+IFBhdGNoIGltcGxlbWVu dHMgY2FsbGJhY2sgZnVuY3Rpb25zIGZvciBub24tZGVmYXVsdCBlbmRwb2ludHMKPiBkZWZpbmVk IGluIHVzYl9lcF9vcHMgb2JqZWN0Lgo+IAo+IFNpZ25lZC1vZmYtYnk6IFBhd2VsIExhc3pjemFr IDxwYXdlbGxAY2FkZW5jZS5jb20+Cj4gLS0tCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2VwMC5jICAg IHwgIDE4ICsrCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jIHwgNDQyICsrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKy0KPiAgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0Lmgg fCAgIDMgKwo+ICAzIGZpbGVzIGNoYW5nZWQsIDQ2MSBpbnNlcnRpb25zKCspLCAyIGRlbGV0aW9u cygtKQo+IAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9lcDAuYyBiL2RyaXZlcnMv dXNiL2NkbnMzL2VwMC5jCj4gaW5kZXggYzA4ZDAyNjY1ZjlkLi5jYTE3OTU0NjcxNTUgMTAwNjQ0 Cj4gLS0tIGEvZHJpdmVycy91c2IvY2RuczMvZXAwLmMKPiArKysgYi9kcml2ZXJzL3VzYi9jZG5z My9lcDAuYwo+IEBAIC0yMyw2ICsyMywyNCBAQCBzdGF0aWMgdm9pZCBjZG5zM19wcmVwYXJlX3Nl dHVwX3BhY2tldChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldikKPiAgCS8vVE9ETzogSW1w bGVtZW50cyB0aGlzIGZ1bmN0aW9uCj4gIH0KPiAgCj4gKy8qKgo+ICsgKiBjZG5zM19nYWRnZXRf ZXBfc2V0X3dlZGdlIFNldCB3ZWRnZSBvbiBzZWxlY3RlZCBlbmRwb2ludAo+ICsgKiBAZXA6IGVu ZHBvaW50IG9iamVjdAo+ICsgKgo+ICsgKiBSZXR1cm5zIDAKPiArICovCj4gK2ludCBjZG5zM19n YWRnZXRfZXBfc2V0X3dlZGdlKHN0cnVjdCB1c2JfZXAgKmVwKQo+ICt7Cj4gKwlzdHJ1Y3QgY2Ru czNfZW5kcG9pbnQgKnByaXZfZXAgPSBlcF90b19jZG5zM19lcChlcCk7Cj4gKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKPiArCj4gKwlkZXZfZGJn KCZwcml2X2Rldi0+ZGV2LCAiV2VkZ2UgZm9yICVzXG4iLCBlcC0+bmFtZSk7Cj4gKwljZG5zM19n YWRnZXRfZXBfc2V0X2hhbHQoZXAsIDEpOwo+ICsJcHJpdl9lcC0+ZmxhZ3MgfD0gRVBfV0VER0U7 Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gIC8qKgo+ICAgKiBjZG5zM19lcDBfY29uZmln IC0gQ29uZmlndXJlcyBkZWZhdWx0IGVuZHBvaW50Cj4gICAqIEBwcml2X2RldjogZXh0ZW5kZWQg Z2FkZ2V0IG9iamVjdAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYyBi L2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jCj4gaW5kZXggNzAyYTA1ZmFhNjY0Li4xZjJhNDM0 NDg2ZGMgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmMKPiArKysgYi9k cml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYwo+IEBAIC01OCw2ICs1OCwxOSBAQCB2b2lkIGNkbnMz X3NldF9yZWdpc3Rlcl9iaXQodm9pZCBfX2lvbWVtICpwdHIsIHUzMiBtYXNrKQo+ICAJd3JpdGVs KG1hc2ssIHB0cik7Cj4gIH0KPiAgCj4gKy8qKgo+ICsgKiBjZG5zM19uZXh0X3JlcXVlc3QgLSBy ZXR1cm5zIG5leHQgcmVxdWVzdCBmcm9tIGxpc3QKPiArICogQGxpc3Q6IGxpc3QgY29udGFpbmlu ZyByZXF1ZXN0cwo+ICsgKgo+ICsgKiBSZXR1cm5zIHJlcXVlc3Qgb3IgTlVMTCBpZiBubyByZXF1 ZXN0cyBpbiBsaXN0Cj4gKyAqLwo+ICtzdHJ1Y3QgdXNiX3JlcXVlc3QgKmNkbnMzX25leHRfcmVx dWVzdChzdHJ1Y3QgbGlzdF9oZWFkICpsaXN0KQo+ICt7Cj4gKwlpZiAobGlzdF9lbXB0eShsaXN0 KSkKPiArCQlyZXR1cm4gTlVMTDsKPiArCXJldHVybiBsaXN0X2ZpcnN0X2VudHJ5KGxpc3QsIHN0 cnVjdCB1c2JfcmVxdWVzdCwgbGlzdCk7Cj4gK30KPiArCj4gIC8qKgo+ICAgKiBzZWxlY3RfZXAg LSBzZWxlY3RzIGVuZHBvaW50Cj4gICAqIEBwcml2X2RldjogIGV4dGVuZGVkIGdhZGdldCBvYmpl Y3QKPiBAQCAtNzMsNiArODYsNTMgQEAgdm9pZCBjZG5zM19zZWxlY3RfZXAoc3RydWN0IGNkbnMz X2RldmljZSAqcHJpdl9kZXYsIHUzMiBlcCkKPiAgCXdyaXRlbChlcCwgJnByaXZfZGV2LT5yZWdz LT5lcF9zZWwpOwo+ICB9Cj4gIAo+ICsvKioKPiArICogY2RuczNfYWxsb2NhdGVfdHJiX3Bvb2wg LSBBbGxvY2F0ZXMgVFJCJ3MgcG9vbCBmb3Igc2VsZWN0ZWQgZW5kcG9pbnQKPiArICogQHByaXZf ZXA6ICBlbmRwb2ludCBvYmplY3QKPiArICoKPiArICogRnVuY3Rpb24gd2lsbCByZXR1cm4gMCBv biBzdWNjZXNzIG9yIC1FTk9NRU0gb24gYWxsb2NhdGlvbiBlcnJvcgo+ICsgKi8KPiArc3RhdGlj IGludCBjZG5zM19hbGxvY2F0ZV90cmJfcG9vbChzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZf ZXApCj4gK3sKPiArCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2Ru czNfZGV2Owo+ICsJc3RydWN0IGNkbnMzX3RyYiAqbGlua190cmI7Cj4gKwo+ICsJaWYgKCFwcml2 X2VwLT50cmJfcG9vbCkgewo+ICsJCXByaXZfZXAtPnRyYl9wb29sID0gZG1hX3phbGxvY19jb2hl cmVudChwcml2X2Rldi0+c3lzZGV2LAo+ICsJCQkJCQkJVFJCX1JJR05fU0laRSwKClRSQl9SSU5H X1NJWkUKCj4gKwkJCQkJCQkmcHJpdl9lcC0+dHJiX3Bvb2xfZG1hLAo+ICsJCQkJCQkJR0ZQX0RN QSk7Cj4gKwkJaWYgKCFwcml2X2VwLT50cmJfcG9vbCkKPiArCQkJcmV0dXJuIC1FTk9NRU07Cj4g Kwl9IGVsc2Ugewo+ICsJCW1lbXNldChwcml2X2VwLT50cmJfcG9vbCwgMCwgVFJCX1JJR05fU0la RSk7CgpoZXJlIHRvby4KCj4gKwl9Cj4gKwo+ICsJaWYgKCFwcml2X2VwLT5hbGlnbmVkX2J1ZmYp IHsKPiArCQlwcml2X2VwLT5hbGlnbmVkX2J1ZmYgPSBkbWFfYWxsb2NfY29oZXJlbnQocHJpdl9k ZXYtPnN5c2RldiwKPiArCQkJCQkJCSAgIENETlMzX1VOQUxJR05FRF9CVUZfU0laRSwKCkNETlMz X0FMSUdORURfQlVGX1NJWkUKCj4gKwkJCQkJCQkgICAmcHJpdl9lcC0+YWxpZ25lZF9kbWFfYWRk ciwKPiArCQkJCQkJCSAgIEdGUF9ETUEpOwo+ICsJCWlmICghcHJpdl9lcC0+YWxpZ25lZF9idWZm KSB7Cj4gKwkJCWRtYV9mcmVlX2NvaGVyZW50KHByaXZfZGV2LT5zeXNkZXYsCj4gKwkJCQkJICBU UkJfUklHTl9TSVpFLAo+ICsJCQkJCSAgcHJpdl9lcC0+dHJiX3Bvb2wsCj4gKwkJCQkJICBwcml2 X2VwLT50cmJfcG9vbF9kbWEpOwo+ICsJCQlwcml2X2VwLT50cmJfcG9vbCA9IE5VTEw7Cj4gKwo+ ICsJCQlyZXR1cm4gLUVOT01FTTsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJLyogSW5pdGlhbGl6ZSB0 aGUgbGFzdCBUUkIgYXMgTGluayBUUkIgKi8KPiArCWxpbmtfdHJiID0gKHByaXZfZXAtPnRyYl9w b29sICsgVFJCU19QRVJfU0VHTUVOVCAtIDEpOwo+ICsJbGlua190cmItPmJ1ZmZlciA9IFRSQl9C VUZGRVIocHJpdl9lcC0+dHJiX3Bvb2xfZG1hKTsKPiArCWxpbmtfdHJiLT5jb250cm9sID0gVFJC X0NZQ0xFIHwgVFJCX1RZUEUoVFJCX0xJTkspIHwKPiArCQkJICAgIFRSQl9DSEFJTiB8IFRSQl9U T0dHTEU7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gIHN0YXRpYyB2b2lkIGNkbnMzX2Zy ZWVfdHJiX3Bvb2woc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKQo+ICB7Cj4gIAlzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKPiBAQCAtOTIs NiArMTUyLDczIEBAIHN0YXRpYyB2b2lkIGNkbnMzX2ZyZWVfdHJiX3Bvb2woc3RydWN0IGNkbnMz X2VuZHBvaW50ICpwcml2X2VwKQo+ICAJfQo+ICB9Cj4gIAo+ICsvKioKPiArICogY2RuczNfZGF0 YV9mbHVzaCAtIGZsdXNoIGRhdGEgYXQgb25jaGlwIGJ1ZmZlcgo+ICsgKiBAcHJpdl9lcDogZW5k cG9pbnQgb2JqZWN0Cj4gKyAqCj4gKyAqIEVuZHBvaW50IG11c3QgYmUgc2VsZWN0ZWQgYmVmb3Jl IGNhbGwgdG8gdGhpcyBmdW5jdGlvbgo+ICsgKgo+ICsgKiBSZXR1cm5zIHplcm8gb24gc3VjY2Vz cyBvciBuZWdhdGl2ZSB2YWx1ZSBvbiBmYWlsdXJlCj4gKyAqLwo+ICtzdGF0aWMgaW50IGNkbnMz X2RhdGFfZmx1c2goc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKQo+ICt7Cj4gKwlzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKPiArCj4gKwl3 cml0ZWwoRVBfQ01EX0RGTFVTSCwgJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQpOwo+ICsKPiArCS8q IHdhaXQgZm9yIERGTFVTSCBjbGVhcmVkICovCj4gKwlyZXR1cm4gY2RuczNfaGFuZHNoYWtlKCZw cml2X2Rldi0+cmVncy0+ZXBfY21kLCBFUF9DTURfREZMVVNILCAwLCAxMDApOwo+ICt9Cj4gKwo+ ICsvKioKPiArICogY2RuczNfZXBfc3RhbGxfZmx1c2ggLSBTdGFsbHMgYW5kIGZsdXNoZXMgc2Vs ZWN0ZWQgZW5kcG9pbnQKPiArICogQHByaXZfZXA6IGVuZHBvaW50IG9iamVjdAo+ICsgKgo+ICsg KiBFbmRwb2ludCBtdXN0IGJlIHNlbGVjdGVkIGJlZm9yZSBjYWxsIHRvIHRoaXMgZnVuY3Rpb24K PiArICovCj4gK3N0YXRpYyB2b2lkIGNkbnMzX2VwX3N0YWxsX2ZsdXNoKHN0cnVjdCBjZG5zM19l bmRwb2ludCAqcHJpdl9lcCkKPiArewo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYg PSBwcml2X2VwLT5jZG5zM19kZXY7Cj4gKwo+ICsJd3JpdGVsKEVQX0NNRF9ERkxVU0ggfCBFUF9D TURfRVJEWSB8IEVQX0NNRF9TU1RBTEwsCj4gKwkgICAgICAgJnByaXZfZGV2LT5yZWdzLT5lcF9j bWQpOwo+ICsKPiArCS8qIHdhaXQgZm9yIERGTFVTSCBjbGVhcmVkICovCj4gKwljZG5zM19oYW5k c2hha2UoJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQsIEVQX0NNRF9ERkxVU0gsIDAsIDEwMCk7Cj4g Kwlwcml2X2VwLT5mbGFncyB8PSBFUF9TVEFMTDsKPiArfQo+ICsKPiArLyoqCj4gKyAqIGNkbnMz X2dhZGdldF9naXZlYmFjayAtIGNhbGwgc3RydWN0IHVzYl9yZXF1ZXN0J3MgLT5jb21wbGV0ZSBj YWxsYmFjawo+ICsgKiBAcHJpdl9lcDogVGhlIGVuZHBvaW50IHRvIHdob20gdGhlIHJlcXVlc3Qg YmVsb25ncyB0bwo+ICsgKiBAcHJpdl9yZXE6IFRoZSByZXF1ZXN0IHdlJ3JlIGdpdmluZyBiYWNr Cj4gKyAqIEBzdGF0dXM6IGNvbXBsZXRpb24gY29kZSBmb3IgdGhlIHJlcXVlc3QKPiArICoKPiAr ICogTXVzdCBiZSBjYWxsZWQgd2l0aCBjb250cm9sbGVyJ3MgbG9jayBoZWxkIGFuZCBpbnRlcnJ1 cHRzIGRpc2FibGVkLiBUaGlzCj4gKyAqIGZ1bmN0aW9uIHdpbGwgdW5tYXAgQHJlcSBhbmQgY2Fs bCBpdHMgLT5jb21wbGV0ZSgpIGNhbGxiYWNrIHRvIG5vdGlmeSB1cHBlcgo+ICsgKiBsYXllcnMg dGhhdCBpdCBoYXMgY29tcGxldGVkLgo+ICsgKi8KPiArdm9pZCBjZG5zM19nYWRnZXRfZ2l2ZWJh Y2soc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAo+ICsJCQkgICBzdHJ1Y3QgY2RuczNf cmVxdWVzdCAqcHJpdl9yZXEsCj4gKwkJCSAgIGludCBzdGF0dXMpCj4gK3sKPiArCS8vVE9ETzog SW1wbGVtZW50cyB0aGlzIGZ1bmN0aW9uLgo+ICt9Cj4gKwo+ICsvKioKPiArICogY2RuczNfZXBf cnVuX3RyYW5zZmVyIC0gc3RhcnQgdHJhbnNmZXIgb24gbm8tZGVmYXVsdCBlbmRwb2ludCBoYXJk d2FyZQo+ICsgKiBAcHJpdl9lcDogZW5kcG9pbnQgb2JqZWN0Cj4gKyAqCj4gKyAqIFJldHVybnMg emVybyBvbiBzdWNjZXNzIG9yIG5lZ2F0aXZlIHZhbHVlIG9uIGZhaWx1cmUKPiArICovCj4gK2lu dCBjZG5zM19lcF9ydW5fdHJhbnNmZXIoc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAo+ ICsJCQkgIHN0cnVjdCB1c2JfcmVxdWVzdCAqcmVxdWVzdCkKPiArewo+ICsJLy9UT0RPOiBJbXBs ZW1lbnRzIHRoaXMgZnVuY3Rpb24uCj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gIC8qKgo+ ICAgKiBjZG5zM19pcnFfaGFuZGxlciAtIGlycSBsaW5lIGludGVycnVwdCBoYW5kbGVyCj4gICAq IEBjZG5zOiBjZG5zMyBpbnN0YW5jZQo+IEBAIC0xNzAsNiArMjk3LDMxOCBAQCBzdGF0aWMgc3Ry dWN0IHVzYl9lcCAqY2RuczNfZ2FkZ2V0X21hdGNoX2VwKHN0cnVjdCB1c2JfZ2FkZ2V0ICpnYWRn ZXQsCj4gIAlyZXR1cm4gJnByaXZfZXAtPmVuZHBvaW50Owo+ICB9Cj4gIAo+ICsvKioKPiArICog Y2RuczNfZ2FkZ2V0X2VwX2VuYWJsZSBFbmFibGUgZW5kcG9pbnQKPiArICogQGVwOiBlbmRwb2lu dCBvYmplY3QKPiArICogQGRlc2M6IGVuZHBvaW50IGRlc2NyaXB0b3IKPiArICoKPiArICogUmV0 dXJucyAwIG9uIHN1Y2Nlc3MsIGVycm9yIGNvZGUgZWxzZXdoZXJlCj4gKyAqLwo+ICtzdGF0aWMg aW50IGNkbnMzX2dhZGdldF9lcF9lbmFibGUoc3RydWN0IHVzYl9lcCAqZXAsCj4gKwkJCQkgIGNv bnN0IHN0cnVjdCB1c2JfZW5kcG9pbnRfZGVzY3JpcHRvciAqZGVzYykKPiArewo+ICsJc3RydWN0 IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwOwo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9k ZXY7Cj4gKwl1bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJaW50IHJldDsKPiArCXUzMiByZWc7Cj4g Kwo+ICsJcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsKPiArCXByaXZfZGV2ID0gcHJpdl9l cC0+Y2RuczNfZGV2Owo+ICsKPiArCWlmICghZXAgfHwgIWRlc2MgfHwgZGVzYy0+YkRlc2NyaXB0 b3JUeXBlICE9IFVTQl9EVF9FTkRQT0lOVCkgewo+ICsJCWRldl9lcnIoJnByaXZfZGV2LT5kZXYs ICJ1c2JzczogaW52YWxpZCBwYXJhbWV0ZXJzXG4iKTsKCmRldl9kYmcoKT8KCkdhZGdldCBkcml2 ZXIgd2lsbCBiZSBtb3JlIHZlcmJvc2UuCgo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsK PiArCWlmICghZGVzYy0+d01heFBhY2tldFNpemUpIHsKPiArCQlkZXZfZXJyKCZwcml2X2Rldi0+ ZGV2LCAidXNic3M6IG1pc3Npbmcgd01heFBhY2tldFNpemVcbiIpOwo+ICsJCXJldHVybiAtRUlO VkFMOwo+ICsJfQo+ICsKPiArCWlmIChkZXZfV0FSTl9PTkNFKCZwcml2X2Rldi0+ZGV2LCBwcml2 X2VwLT5mbGFncyAmIEVQX0VOQUJMRUQsCj4gKwkJCSAgIiVzIGlzIGFscmVhZHkgZW5hYmxlZFxu IiwgcHJpdl9lcC0+bmFtZSkpCj4gKwkJcmV0dXJuIDA7Cj4gKwo+ICsJcmV0ID0gY2RuczNfYWxs b2NhdGVfdHJiX3Bvb2wocHJpdl9lcCk7Cj4gKwlpZiAocmV0KQo+ICsJCXJldHVybiByZXQ7CgpX aHkgbm90IGFsbG9jYXRlIHRoZSBUUkIgcG9vbCBvbmNlIGZvciBhbGwgZW5kcG9pbnRzIGF0IGdh ZGdldCBpbml0PwoKeW91IGRvbid0IHNlZW0gdG8gYmUgY2FsbGluZyBjZG5zM19hbGxvY2F0ZV90 cmJfcG9vbCgpIGluIGNkbnMzX2dhZGdldF9lcF9kaXNhYmxlKCkuCgo+ICsKPiArCWRldl9kYmco JnByaXZfZGV2LT5kZXYsICJFbmFibGluZyBlbmRwb2ludDogJXNcbiIsIGVwLT5uYW1lKTsKPiAr CXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsJY2RuczNfc2Vs ZWN0X2VwKHByaXZfZGV2LCBkZXNjLT5iRW5kcG9pbnRBZGRyZXNzKTsKPiArCXdyaXRlbChFUF9D TURfRVBSU1QsICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKPiArCj4gKwlyZXQgPSBjZG5zM19o YW5kc2hha2UoJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQsCj4gKwkJCSAgICAgIEVQX0NNRF9DU1RB TEwgfCBFUF9DTURfRVBSU1QsIDAsIDEwMCk7Cj4gKwo+ICsJY2RuczNfc2V0X3JlZ2lzdGVyX2Jp dCgmcHJpdl9kZXYtPnJlZ3MtPmVwX2NmZywgRVBfQ0ZHX0VOQUJMRSk7Cj4gKwo+ICsJZXAtPmRl c2MgPSBkZXNjOwo+ICsJcHJpdl9lcC0+ZmxhZ3MgJj0gfihFUF9QRU5ESU5HX1JFUVVFU1QgfCBF UF9TVEFMTCk7Cj4gKwlwcml2X2VwLT5mbGFncyB8PSBFUF9FTkFCTEVEIHwgRVBfVVBEQVRFX0VQ X1RSQkFERFI7Cj4gKwlwcml2X2VwLT5lbnF1ZXVlID0gMDsKPiArCXByaXZfZXAtPmRlcXVldWUg PSAwOwo+ICsJcmVnID0gcmVhZGwoJnByaXZfZGV2LT5yZWdzLT5lcF9zdHMpOwo+ICsJcHJpdl9l cC0+cGNzID0gISFFUF9TVFNfQ0NTKHJlZyk7Cj4gKwlwcml2X2VwLT5jY3MgPSAhIUVQX1NUU19D Q1MocmVnKTsKPiArCS8qIG9uZSBUUkIgaXMgcmVzZXJ2ZWQgZm9yIGxpbmsgVFJCIHVzZWQgaW4g RE1VTFQgbW9kZSovCj4gKwlwcml2X2VwLT5mcmVlX3RyYnMgPSBUUkJTX1BFUl9TRUdNRU5UIC0g MTsKPiArCj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3Mp Owo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19nYWRnZXRfZXBfZGlz YWJsZSBEaXNhYmxlIGVuZHBvaW50Cj4gKyAqIEBlcDogZW5kcG9pbnQgb2JqZWN0Cj4gKyAqCj4g KyAqIFJldHVybnMgMCBvbiBzdWNjZXNzLCBlcnJvciBjb2RlIGVsc2V3aGVyZQo+ICsgKi8KPiAr c3RhdGljIGludCBjZG5zM19nYWRnZXRfZXBfZGlzYWJsZShzdHJ1Y3QgdXNiX2VwICplcCkKPiAr ewo+ICsJc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwOwo+ICsJc3RydWN0IGNkbnMzX2Rl dmljZSAqcHJpdl9kZXY7Cj4gKwl1bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJaW50IHJldCA9IDA7 Cj4gKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3Q7Cj4gKwl1MzIgZXBfY2ZnOwo+ICsKPiAr CWlmICghZXApIHsKPiArCQlwcl9kZWJ1ZygidXNic3M6IGludmFsaWQgcGFyYW1ldGVyc1xuIik7 Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4gKwo+ICsJcHJpdl9lcCA9IGVwX3RvX2NkbnMz X2VwKGVwKTsKPiArCXByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2Owo+ICsKPiArCWlmIChk ZXZfV0FSTl9PTkNFKCZwcml2X2Rldi0+ZGV2LCAhKHByaXZfZXAtPmZsYWdzICYgRVBfRU5BQkxF RCksCj4gKwkJCSAgIiVzIGlzIGFscmVhZHkgZGlzYWJsZWRcbiIsIHByaXZfZXAtPm5hbWUpKQo+ ICsJCXJldHVybiAwOwo+ICsKPiArCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywg ZmxhZ3MpOwo+ICsJaWYgKCFwcml2X2Rldi0+c3RhcnRfZ2FkZ2V0KSB7Cj4gKwkJZGV2X2RiZygm cHJpdl9kZXYtPmRldiwKPiArCQkJIkRpc2FibGluZyBlbmRwb2ludCBhdCBkaXNjb25uZWN0aW9u OiAlc1xuIiwgZXAtPm5hbWUpOwoKVGhpcyBmbGFnIGlzIGxvb2tpbmcgdmVyeSB0cmlja3kuCldo YXQgZG8geW91IG1lYW4gYnkgImRpc2FibGluZyBhdCBkaXNjb25uZWN0aW9uIj8KCj4gKwkJc3Bp bl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKPiArCQlyZXR1cm4g MDsKCkVQIGlzIG5vdCB5ZXQgZGlzYWJsZWQgYW5kIHdlJ3JlIHJldHVybmluZyAwLiBUaGlzIHdp bGwgY2F1c2UgYW4gdW5iYWxhbmNlLgpJJ2QgYXZvaWQgdGhhdCBmbGFnIGFsdG9nZXRoZXIuCgo+ ICsJfQo+ICsKPiArCWRldl9kYmcoJnByaXZfZGV2LT5kZXYsICJEaXNhYmxpbmcgZW5kcG9pbnQ6 ICVzXG4iLCBlcC0+bmFtZSk7Cj4gKwo+ICsJY2RuczNfc2VsZWN0X2VwKHByaXZfZGV2LCBlcC0+ ZGVzYy0+YkVuZHBvaW50QWRkcmVzcyk7Cj4gKwlyZXQgPSBjZG5zM19kYXRhX2ZsdXNoKHByaXZf ZXApOwo+ICsJd2hpbGUgKCFsaXN0X2VtcHR5KCZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpKSB7Cj4g KwkJcmVxdWVzdCA9IGNkbnMzX25leHRfcmVxdWVzdCgmcHJpdl9lcC0+cmVxdWVzdF9saXN0KTsK PiArCj4gKwkJY2RuczNfZ2FkZ2V0X2dpdmViYWNrKHByaXZfZXAsIHRvX2NkbnMzX3JlcXVlc3Qo cmVxdWVzdCksCj4gKwkJCQkgICAgICAtRVNIVVRET1dOKTsKPiArCX0KPiArCj4gKwllcF9jZmcg PSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPmVwX2NmZyk7Cj4gKwllcF9jZmcgJj0gfkVQX0NGR19F TkFCTEU7Cj4gKwl3cml0ZWwoZXBfY2ZnLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX2NmZyk7Cj4gKwll cC0+ZGVzYyA9IE5VTEw7Cj4gKwlwcml2X2VwLT5mbGFncyAmPSB+RVBfRU5BQkxFRDsKPiArCj4g KwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsKPiAr CXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19nYWRnZXRfZXBfYWxsb2Nf cmVxdWVzdCBBbGxvY2F0ZXMgcmVxdWVzdAo+ICsgKiBAZXA6IGVuZHBvaW50IG9iamVjdCBhc3Nv Y2lhdGVkIHdpdGggcmVxdWVzdAo+ICsgKiBAZ2ZwX2ZsYWdzOiBnZnAgZmxhZ3MKPiArICoKPiAr ICogUmV0dXJucyBhbGxvY2F0ZWQgcmVxdWVzdCBhZGRyZXNzLCBOVUxMIG9uIGFsbG9jYXRpb24g ZXJyb3IKPiArICovCj4gK3N0cnVjdCB1c2JfcmVxdWVzdCAqY2RuczNfZ2FkZ2V0X2VwX2FsbG9j X3JlcXVlc3Qoc3RydWN0IHVzYl9lcCAqZXAsCj4gKwkJCQkJCSAgZ2ZwX3QgZ2ZwX2ZsYWdzKQo+ ICt7Cj4gKwlzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAgPSBlcF90b19jZG5zM19lcChl cCk7Cj4gKwlzdHJ1Y3QgY2RuczNfcmVxdWVzdCAqcHJpdl9yZXE7Cj4gKwo+ICsJcHJpdl9yZXEg PSBremFsbG9jKHNpemVvZigqcHJpdl9yZXEpLCBnZnBfZmxhZ3MpOwo+ICsJaWYgKCFwcml2X3Jl cSkKPiArCQlyZXR1cm4gTlVMTDsKPiArCj4gKwlwcml2X3JlcS0+cHJpdl9lcCA9IHByaXZfZXA7 Cj4gKwo+ICsJcmV0dXJuICZwcml2X3JlcS0+cmVxdWVzdDsKPiArfQo+ICsKPiArLyoqCj4gKyAq IGNkbnMzX2dhZGdldF9lcF9mcmVlX3JlcXVlc3QgRnJlZSBtZW1vcnkgb2NjdXBpZWQgYnkgcmVx dWVzdAo+ICsgKiBAZXA6IGVuZHBvaW50IG9iamVjdCBhc3NvY2lhdGVkIHdpdGggcmVxdWVzdAo+ ICsgKiBAcmVxdWVzdDogcmVxdWVzdCB0byBmcmVlIG1lbW9yeQo+ICsgKi8KPiArdm9pZCBjZG5z M19nYWRnZXRfZXBfZnJlZV9yZXF1ZXN0KHN0cnVjdCB1c2JfZXAgKmVwLAo+ICsJCQkJICBzdHJ1 Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3QpCj4gK3sKPiArCXN0cnVjdCBjZG5zM19yZXF1ZXN0ICpw cml2X3JlcSA9IHRvX2NkbnMzX3JlcXVlc3QocmVxdWVzdCk7Cj4gKwo+ICsJa2ZyZWUocHJpdl9y ZXEpOwo+ICt9Cj4gKwo+ICsvKioKPiArICogY2RuczNfZ2FkZ2V0X2VwX3F1ZXVlIFRyYW5zZmVy IGRhdGEgb24gZW5kcG9pbnQKPiArICogQGVwOiBlbmRwb2ludCBvYmplY3QKPiArICogQHJlcXVl c3Q6IHJlcXVlc3Qgb2JqZWN0Cj4gKyAqIEBnZnBfZmxhZ3M6IGdmcCBmbGFncwo+ICsgKgo+ICsg KiBSZXR1cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUKPiArICovCj4gK3N0 YXRpYyBpbnQgX19jZG5zM19nYWRnZXRfZXBfcXVldWUoc3RydWN0IHVzYl9lcCAqZXAsCj4gKwkJ CQkgICBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3QsCj4gKwkJCQkgICBnZnBfdCBnZnBfZmxh Z3MpCj4gK3sKPiArCXN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMz X2VwKGVwKTsKPiArCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2Ru czNfZGV2Owo+ICsJaW50IHJldCA9IDA7Cj4gKwo+ICsJcmVxdWVzdC0+YWN0dWFsID0gMDsKPiAr CXJlcXVlc3QtPnN0YXR1cyA9IC1FSU5QUk9HUkVTUzsKPiArCj4gKwlkZXZfZGJnKCZwcml2X2Rl di0+ZGV2LCAiUXVldWluZyB0byBlbmRwb2ludDogJXNcbiIsIHByaXZfZXAtPm5hbWUpOwo+ICsK PiArCXJldCA9IHVzYl9nYWRnZXRfbWFwX3JlcXVlc3RfYnlfZGV2KHByaXZfZGV2LT5zeXNkZXYs IHJlcXVlc3QsCj4gKwkJCQkJICAgIHVzYl9lbmRwb2ludF9kaXJfaW4oZXAtPmRlc2MpKTsKPiAr Cj4gKwlpZiAocmV0KQo+ICsJCXJldHVybiByZXQ7Cj4gKwo+ICsJaWYgKCFjZG5zM19lcF9ydW5f dHJhbnNmZXIocHJpdl9lcCwgcmVxdWVzdCkpCj4gKwkJbGlzdF9hZGRfdGFpbCgmcmVxdWVzdC0+ bGlzdCwgJnByaXZfZXAtPnJlcXVlc3RfbGlzdCk7Cgpob3cgYWJvdXQgY2F0Y2hpbmcgdGhlIHJl dHVybiB2YWx1ZSBpZiBjZG5zM19lcF9ydW5fdHJhbnNmZXIoKSBmYWlscz8KCj4gKwo+ICsJcmV0 dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGludCBjZG5zM19nYWRnZXRfZXBfcXVldWUoc3Ry dWN0IHVzYl9lcCAqZXAsIHN0cnVjdCB1c2JfcmVxdWVzdCAqcmVxdWVzdCwKPiArCQkJCSBnZnBf dCBnZnBfZmxhZ3MpCj4gK3sKPiArCXN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVw X3RvX2NkbnMzX2VwKGVwKTsKPiArCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJp dl9lcC0+Y2RuczNfZGV2Owo+ICsJc3RydWN0IHVzYl9yZXF1ZXN0ICp6bHBfcmVxdWVzdDsKPiAr CXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXNwaW5fbG9ja19pcnFz YXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsJcmV0ID0gX19jZG5zM19nYWRnZXRfZXBf cXVldWUoZXAsIHJlcXVlc3QsIGdmcF9mbGFncyk7Cj4gKwo+ICsJaWYgKHJldCA9PSAwICYmIHJl cXVlc3QtPnplcm8gJiYgcmVxdWVzdC0+bGVuZ3RoICYmCj4gKwkgICAgKHJlcXVlc3QtPmxlbmd0 aCAlIGVwLT5tYXhwYWNrZXQgPT0gMCkpIHsKPiArCQl6bHBfcmVxdWVzdCA9IGNkbnMzX2dhZGdl dF9lcF9hbGxvY19yZXF1ZXN0KGVwLCBHRlBfQVRPTUlDKTsKPiArCQl6bHBfcmVxdWVzdC0+YnVm ID0gcHJpdl9kZXYtPnpscF9idWY7Cj4gKwkJemxwX3JlcXVlc3QtPmxlbmd0aCA9IDA7Cj4gKwo+ ICsJCWRldl9kYmcoJnByaXZfZGV2LT5kZXYsICJRdWV1aW5nIFpMUCBmb3IgZW5kcG9pbnQ6ICVz XG4iLAo+ICsJCQlwcml2X2VwLT5uYW1lKTsKPiArCQlyZXQgPSBfX2NkbnMzX2dhZGdldF9lcF9x dWV1ZShlcCwgemxwX3JlcXVlc3QsIGdmcF9mbGFncyk7CgpXaG8gaXMgZ29pbmcgdG8gZnJlZSB0 aGlzIHpscF9yZXF1ZXN0PwoKPiArCX0KPiArCj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZw cml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArLyoqCj4g KyAqIGNkbnMzX2dhZGdldF9lcF9kZXF1ZXVlIFJlbW92ZSByZXF1ZXN0IGZyb20gdHJhbnNmZXIg cXVldWUKPiArICogQGVwOiBlbmRwb2ludCBvYmplY3QgYXNzb2NpYXRlZCB3aXRoIHJlcXVlc3QK PiArICogQHJlcXVlc3Q6IHJlcXVlc3Qgb2JqZWN0Cj4gKyAqCj4gKyAqIFJldHVybnMgMCBvbiBz dWNjZXNzLCBlcnJvciBjb2RlIGVsc2V3aGVyZQo+ICsgKi8KPiAraW50IGNkbnMzX2dhZGdldF9l cF9kZXF1ZXVlKHN0cnVjdCB1c2JfZXAgKmVwLAo+ICsJCQkgICAgc3RydWN0IHVzYl9yZXF1ZXN0 ICpyZXF1ZXN0KQo+ICt7Cj4gKwlzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAgPSBlcF90 b19jZG5zM19lcChlcCk7Cj4gKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZf ZXAtPmNkbnMzX2RldjsKPiArCXN0cnVjdCB1c2JfcmVxdWVzdCAqcmVxLCAqcmVxX3RlbXA7Cj4g Kwl1bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJaW50IHJldCA9IDA7Cj4gKwo+ICsJaWYgKCFlcCB8 fCAhcmVxdWVzdCB8fCAhZXAtPmRlc2MpCj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJc3Bp bl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7Cj4gKwlkZXZfZGJnKCZwcml2 X2Rldi0+ZGV2LCAiRGVxdWV1ZSBmcm9tICVzXG4iLCBlcC0+bmFtZSk7Cj4gKwo+ICsJY2RuczNf c2VsZWN0X2VwKHByaXZfZGV2LCBlcC0+ZGVzYy0+YkVuZHBvaW50QWRkcmVzcyk7Cj4gKwlpZiAo cHJpdl9kZXYtPnN0YXJ0X2dhZGdldCkKPiArCQlyZXQgPSBjZG5zM19kYXRhX2ZsdXNoKHByaXZf ZXApOwo+ICsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnlfc2FmZShyZXEsIHJlcV90ZW1wLCAmcHJp dl9lcC0+cmVxdWVzdF9saXN0LCBsaXN0KSB7Cj4gKwkJaWYgKHJlcXVlc3QgPT0gcmVxKSB7Cj4g KwkJCWNkbnMzX2dhZGdldF9naXZlYmFjayhwcml2X2VwLAo+ICsJCQkJCSAgICAgIHRvX2NkbnMz X3JlcXVlc3QocmVxdWVzdCksCj4gKwkJCQkJICAgICAgLUVDT05OUkVTRVQpOwo+ICsJCQlicmVh azsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYt PmxvY2ssIGZsYWdzKTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5z M19nYWRnZXRfZXBfc2V0X2hhbHQgU2V0cy9jbGVhcnMgc3RhbGwgb24gc2VsZWN0ZWQgZW5kcG9p bnQKPiArICogQGVwOiBlbmRwb2ludCBvYmplY3QgdG8gc2V0L2NsZWFyIHN0YWxsIG9uCj4gKyAq IEB2YWx1ZTogMSBmb3Igc2V0IHN0YWxsLCAwIGZvciBjbGVhciBzdGFsbAo+ICsgKgo+ICsgKiBS ZXR1cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUKPiArICovCj4gK2ludCBj ZG5zM19nYWRnZXRfZXBfc2V0X2hhbHQoc3RydWN0IHVzYl9lcCAqZXAsIGludCB2YWx1ZSkKPiAr ewo+ICsJc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwID0gZXBfdG9fY2RuczNfZXAoZXAp Owo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYgPSBwcml2X2VwLT5jZG5zM19kZXY7 Cj4gKwl1bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJaW50IHJldCA9IDA7Cj4gKwo+ICsJaWYgKCEo cHJpdl9lcC0+ZmxhZ3MgJiBFUF9FTkFCTEVEKSkKPiArCQlyZXR1cm4gLUVQRVJNOwo+ICsKPiAr CS8qIGlmIGFjdHVhbCB0cmFuc2ZlciBpcyBwZW5kaW5nIGRlZmVyIHNldHRpbmcgc3RhbGwgb24g dGhpcyBlbmRwb2ludCAqLwo+ICsJaWYgKChwcml2X2VwLT5mbGFncyAmIEVQX1BFTkRJTkdfUkVR VUVTVCkgJiYgdmFsdWUpIHsKPiArCQlwcml2X2VwLT5mbGFncyB8PSBFUF9TVEFMTDsKPiArCQly ZXR1cm4gMDsKPiArCX0KPiArCj4gKwlkZXZfZGJnKCZwcml2X2Rldi0+ZGV2LCAiSGFsdCBlbmRw b2ludCAlc1xuIiwgcHJpdl9lcC0+bmFtZSk7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnBy aXZfZGV2LT5sb2NrLCBmbGFncyk7CgpIb3cgYWJvdXQgZ3JhYmJpbmcgdGhlIGxvY2sgYmVmb3Jl IGNoZWNraW5nIGZvciBwcml2LT5lcC0+ZmxhZ3M/Cgo+ICsKPiArCWNkbnMzX3NlbGVjdF9lcChw cml2X2RldiwgZXAtPmRlc2MtPmJFbmRwb2ludEFkZHJlc3MpOwo+ICsJaWYgKHZhbHVlKSB7Cj4g KwkJY2RuczNfZXBfc3RhbGxfZmx1c2gocHJpdl9lcCk7Cj4gKwl9IGVsc2Ugewo+ICsJCXByaXZf ZXAtPmZsYWdzICY9IH5FUF9XRURHRTsKPiArCQl3cml0ZWwoRVBfQ01EX0NTVEFMTCB8IEVQX0NN RF9FUFJTVCwgJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQpOwo+ICsKPiArCQkvKiB3YWl0IGZvciBF UFJTVCBjbGVhcmVkICovCj4gKwkJcmV0ID0gY2RuczNfaGFuZHNoYWtlKCZwcml2X2Rldi0+cmVn cy0+ZXBfY21kLAo+ICsJCQkJICAgICAgRVBfQ01EX0VQUlNULCAwLCAxMDApOwoKaWYgdGhlcmUg d2FzIGFuIGVycm9yIHdlIHNob3VsZG4ndCBiZSBjbGVhcmluZyB0aGUgRVBfU1RBTEwgcmlnaHQK YW5kIGxlYXZlIHRoZSBwZW5kaW5nIGZsYWc/Cgo+ICsJCXByaXZfZXAtPmZsYWdzICY9IH5FUF9T VEFMTDsKPiArCX0KPiArCj4gKwlwcml2X2VwLT5mbGFncyAmPSB+RVBfUEVORElOR19SRVFVRVNU Owo+ICsJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKPiAr Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtleHRlcm4gY29uc3Qgc3RydWN0IHVzYl9lcF9v cHMgY2RuczNfZ2FkZ2V0X2VwMF9vcHM7Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHVzYl9l cF9vcHMgY2RuczNfZ2FkZ2V0X2VwX29wcyA9IHsKPiArCS5lbmFibGUgPSBjZG5zM19nYWRnZXRf ZXBfZW5hYmxlLAo+ICsJLmRpc2FibGUgPSBjZG5zM19nYWRnZXRfZXBfZGlzYWJsZSwKPiArCS5h bGxvY19yZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2VwX2FsbG9jX3JlcXVlc3QsCj4gKwkuZnJlZV9y ZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2VwX2ZyZWVfcmVxdWVzdCwKPiArCS5xdWV1ZSA9IGNkbnMz X2dhZGdldF9lcF9xdWV1ZSwKPiArCS5kZXF1ZXVlID0gY2RuczNfZ2FkZ2V0X2VwX2RlcXVldWUs Cj4gKwkuc2V0X2hhbHQgPSBjZG5zM19nYWRnZXRfZXBfc2V0X2hhbHQsCj4gKwkuc2V0X3dlZGdl ID0gY2RuczNfZ2FkZ2V0X2VwX3NldF93ZWRnZSwKPiArfTsKPiArCj4gIC8qKgo+ICAgKiBjZG5z M19nYWRnZXRfZ2V0X2ZyYW1lIFJldHVybnMgbnVtYmVyIG9mIGFjdHVhbCBJVFAgZnJhbWUKPiAg ICogQGdhZGdldDogZ2FkZ2V0IG9iamVjdAo+IEBAIC0zNjUsOCArODA0LDcgQEAgc3RhdGljIGlu dCBjZG5zM19pbml0X2VwKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2KQo+ICAJCXVzYl9l cF9zZXRfbWF4cGFja2V0X2xpbWl0KCZwcml2X2VwLT5lbmRwb2ludCwKPiAgCQkJCQkgICBFTkRQ T0lOVF9NQVhfUEFDS0VUX0xJTUlUKTsKPiAgCQlwcml2X2VwLT5lbmRwb2ludC5tYXhfc3RyZWFt cyA9IEVORFBPSU5UX01BWF9TVFJFQU1TOwo+IC0JCS8vVE9ETzogQWRkIGltcGxlbWVudGF0aW9u IG9mIGNkbnMzX2dhZGdldF9lcF9vcHMKPiAtCQkvL3ByaXZfZXAtPmVuZHBvaW50Lm9wcyA9ICZj ZG5zM19nYWRnZXRfZXBfb3BzOwo+ICsJCXByaXZfZXAtPmVuZHBvaW50Lm9wcyA9ICZjZG5zM19n YWRnZXRfZXBfb3BzOwo+ICAJCWlmIChlcF9kaXIpCj4gIAkJCXByaXZfZXAtPmVuZHBvaW50LmNh cHMuZGlyX2luID0gMTsKPiAgCQllbHNlCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMz L2dhZGdldC5oIGIvZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmgKPiBpbmRleCAzYjBkNGQyZTQ4 MzEuLmE0YmUyODhiMzRjYiAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQu aAo+ICsrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5oCj4gQEAgLTEwNzIsNCArMTA3Miw3 IEBAIHZvaWQgY2RuczNfc2V0X3JlZ2lzdGVyX2JpdCh2b2lkIF9faW9tZW0gKnB0ciwgdTMyIG1h c2spOwo+ICBpbnQgY2RuczNfaW5pdF9lcDAoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYp Owo+ICB2b2lkIGNkbnMzX2VwMF9jb25maWcoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYp Owo+ICB2b2lkIGNkbnMzX3NlbGVjdF9lcChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rldiwg dTMyIGVwKTsKPiAraW50IGNkbnMzX2dhZGdldF9lcF9zZXRfd2VkZ2Uoc3RydWN0IHVzYl9lcCAq ZXApOwo+ICtpbnQgY2RuczNfZ2FkZ2V0X2VwX3NldF9oYWx0KHN0cnVjdCB1c2JfZXAgKmVwLCBp bnQgdmFsdWUpOwo+ICsKPiAgI2VuZGlmIC8qIF9fTElOVVhfQ0ROUzNfR0FER0VUICovCj4gCgpj aGVlcnMsCi1yb2dlcgo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: Roger Quadros Subject: Re: [RFC PATCH v2 09/15] usb:cdns3: EpX operations part of the API Date: Wed, 28 Nov 2018 14:46:10 +0200 Message-ID: <5BFE8E12.9080307@ti.com> References: <1542535751-16079-1-git-send-email-pawell@cadence.com> <1542535751-16079-10-git-send-email-pawell@cadence.com> Mime-Version: 1.0 Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1542535751-16079-10-git-send-email-pawell@cadence.com> Sender: linux-kernel-owner@vger.kernel.org To: Pawel Laszczak , devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com List-Id: devicetree@vger.kernel.org On 18/11/18 12:09, Pawel Laszczak wrote: > Patch implements callback functions for non-default endpoints > defined in usb_ep_ops object. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/cdns3/ep0.c | 18 ++ > drivers/usb/cdns3/gadget.c | 442 ++++++++++++++++++++++++++++++++++++- > drivers/usb/cdns3/gadget.h | 3 + > 3 files changed, 461 insertions(+), 2 deletions(-) > > diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c > index c08d02665f9d..ca1795467155 100644 > --- a/drivers/usb/cdns3/ep0.c > +++ b/drivers/usb/cdns3/ep0.c > @@ -23,6 +23,24 @@ static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) > //TODO: Implements this function > } > > +/** > + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint > + * @ep: endpoint object > + * > + * Returns 0 > + */ > +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + dev_dbg(&priv_dev->dev, "Wedge for %s\n", ep->name); > + cdns3_gadget_ep_set_halt(ep, 1); > + priv_ep->flags |= EP_WEDGE; > + > + return 0; > +} > + > /** > * cdns3_ep0_config - Configures default endpoint > * @priv_dev: extended gadget object > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > index 702a05faa664..1f2a434486dc 100644 > --- a/drivers/usb/cdns3/gadget.c > +++ b/drivers/usb/cdns3/gadget.c > @@ -58,6 +58,19 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) > writel(mask, ptr); > } > > +/** > + * cdns3_next_request - returns next request from list > + * @list: list containing requests > + * > + * Returns request or NULL if no requests in list > + */ > +struct usb_request *cdns3_next_request(struct list_head *list) > +{ > + if (list_empty(list)) > + return NULL; > + return list_first_entry(list, struct usb_request, list); > +} > + > /** > * select_ep - selects endpoint > * @priv_dev: extended gadget object > @@ -73,6 +86,53 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) > writel(ep, &priv_dev->regs->ep_sel); > } > > +/** > + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint > + * @priv_ep: endpoint object > + * > + * Function will return 0 on success or -ENOMEM on allocation error > + */ > +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct cdns3_trb *link_trb; > + > + if (!priv_ep->trb_pool) { > + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, > + TRB_RIGN_SIZE, TRB_RING_SIZE > + &priv_ep->trb_pool_dma, > + GFP_DMA); > + if (!priv_ep->trb_pool) > + return -ENOMEM; > + } else { > + memset(priv_ep->trb_pool, 0, TRB_RIGN_SIZE); here too. > + } > + > + if (!priv_ep->aligned_buff) { > + priv_ep->aligned_buff = dma_alloc_coherent(priv_dev->sysdev, > + CDNS3_UNALIGNED_BUF_SIZE, CDNS3_ALIGNED_BUF_SIZE > + &priv_ep->aligned_dma_addr, > + GFP_DMA); > + if (!priv_ep->aligned_buff) { > + dma_free_coherent(priv_dev->sysdev, > + TRB_RIGN_SIZE, > + priv_ep->trb_pool, > + priv_ep->trb_pool_dma); > + priv_ep->trb_pool = NULL; > + > + return -ENOMEM; > + } > + } > + > + /* Initialize the last TRB as Link TRB */ > + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); > + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); > + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | > + TRB_CHAIN | TRB_TOGGLE; > + > + return 0; > +} > + > static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) > { > struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > @@ -92,6 +152,73 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) > } > } > > +/** > + * cdns3_data_flush - flush data at onchip buffer > + * @priv_ep: endpoint object > + * > + * Endpoint must be selected before call to this function > + * > + * Returns zero on success or negative value on failure > + */ > +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); > + > + /* wait for DFLUSH cleared */ > + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); > +} > + > +/** > + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint > + * @priv_ep: endpoint object > + * > + * Endpoint must be selected before call to this function > + */ > +static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL, > + &priv_dev->regs->ep_cmd); > + > + /* wait for DFLUSH cleared */ > + cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); > + priv_ep->flags |= EP_STALL; > +} > + > +/** > + * cdns3_gadget_giveback - call struct usb_request's ->complete callback > + * @priv_ep: The endpoint to whom the request belongs to > + * @priv_req: The request we're giving back > + * @status: completion code for the request > + * > + * Must be called with controller's lock held and interrupts disabled. This > + * function will unmap @req and call its ->complete() callback to notify upper > + * layers that it has completed. > + */ > +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, > + struct cdns3_request *priv_req, > + int status) > +{ > + //TODO: Implements this function. > +} > + > +/** > + * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware > + * @priv_ep: endpoint object > + * > + * Returns zero on success or negative value on failure > + */ > +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, > + struct usb_request *request) > +{ > + //TODO: Implements this function. > + > + return 0; > +} > + > /** > * cdns3_irq_handler - irq line interrupt handler > * @cdns: cdns3 instance > @@ -170,6 +297,318 @@ static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, > return &priv_ep->endpoint; > } > > +/** > + * cdns3_gadget_ep_enable Enable endpoint > + * @ep: endpoint object > + * @desc: endpoint descriptor > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_gadget_ep_enable(struct usb_ep *ep, > + const struct usb_endpoint_descriptor *desc) > +{ > + struct cdns3_endpoint *priv_ep; > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret; > + u32 reg; > + > + priv_ep = ep_to_cdns3_ep(ep); > + priv_dev = priv_ep->cdns3_dev; > + > + if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { > + dev_err(&priv_dev->dev, "usbss: invalid parameters\n"); dev_dbg()? Gadget driver will be more verbose. > + return -EINVAL; > + } > + > + if (!desc->wMaxPacketSize) { > + dev_err(&priv_dev->dev, "usbss: missing wMaxPacketSize\n"); > + return -EINVAL; > + } > + > + if (dev_WARN_ONCE(&priv_dev->dev, priv_ep->flags & EP_ENABLED, > + "%s is already enabled\n", priv_ep->name)) > + return 0; > + > + ret = cdns3_allocate_trb_pool(priv_ep); > + if (ret) > + return ret; Why not allocate the TRB pool once for all endpoints at gadget init? you don't seem to be calling cdns3_allocate_trb_pool() in cdns3_gadget_ep_disable(). > + > + dev_dbg(&priv_dev->dev, "Enabling endpoint: %s\n", ep->name); > + spin_lock_irqsave(&priv_dev->lock, flags); > + cdns3_select_ep(priv_dev, desc->bEndpointAddress); > + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); > + > + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, > + EP_CMD_CSTALL | EP_CMD_EPRST, 0, 100); > + > + cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE); > + > + ep->desc = desc; > + priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALL); > + priv_ep->flags |= EP_ENABLED | EP_UPDATE_EP_TRBADDR; > + priv_ep->enqueue = 0; > + priv_ep->dequeue = 0; > + reg = readl(&priv_dev->regs->ep_sts); > + priv_ep->pcs = !!EP_STS_CCS(reg); > + priv_ep->ccs = !!EP_STS_CCS(reg); > + /* one TRB is reserved for link TRB used in DMULT mode*/ > + priv_ep->free_trbs = TRBS_PER_SEGMENT - 1; > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_ep_disable Disable endpoint > + * @ep: endpoint object > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_gadget_ep_disable(struct usb_ep *ep) > +{ > + struct cdns3_endpoint *priv_ep; > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret = 0; > + struct usb_request *request; > + u32 ep_cfg; > + > + if (!ep) { > + pr_debug("usbss: invalid parameters\n"); > + return -EINVAL; > + } > + > + priv_ep = ep_to_cdns3_ep(ep); > + priv_dev = priv_ep->cdns3_dev; > + > + if (dev_WARN_ONCE(&priv_dev->dev, !(priv_ep->flags & EP_ENABLED), > + "%s is already disabled\n", priv_ep->name)) > + return 0; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + if (!priv_dev->start_gadget) { > + dev_dbg(&priv_dev->dev, > + "Disabling endpoint at disconnection: %s\n", ep->name); This flag is looking very tricky. What do you mean by "disabling at disconnection"? > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; EP is not yet disabled and we're returning 0. This will cause an unbalance. I'd avoid that flag altogether. > + } > + > + dev_dbg(&priv_dev->dev, "Disabling endpoint: %s\n", ep->name); > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + ret = cdns3_data_flush(priv_ep); > + while (!list_empty(&priv_ep->request_list)) { > + request = cdns3_next_request(&priv_ep->request_list); > + > + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), > + -ESHUTDOWN); > + } > + > + ep_cfg = readl(&priv_dev->regs->ep_cfg); > + ep_cfg &= ~EP_CFG_ENABLE; > + writel(ep_cfg, &priv_dev->regs->ep_cfg); > + ep->desc = NULL; > + priv_ep->flags &= ~EP_ENABLED; > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_alloc_request Allocates request > + * @ep: endpoint object associated with request > + * @gfp_flags: gfp flags > + * > + * Returns allocated request address, NULL on allocation error > + */ > +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_request *priv_req; > + > + priv_req = kzalloc(sizeof(*priv_req), gfp_flags); > + if (!priv_req) > + return NULL; > + > + priv_req->priv_ep = priv_ep; > + > + return &priv_req->request; > +} > + > +/** > + * cdns3_gadget_ep_free_request Free memory occupied by request > + * @ep: endpoint object associated with request > + * @request: request to free memory > + */ > +void cdns3_gadget_ep_free_request(struct usb_ep *ep, > + struct usb_request *request) > +{ > + struct cdns3_request *priv_req = to_cdns3_request(request); > + > + kfree(priv_req); > +} > + > +/** > + * cdns3_gadget_ep_queue Transfer data on endpoint > + * @ep: endpoint object > + * @request: request object > + * @gfp_flags: gfp flags > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, > + struct usb_request *request, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + int ret = 0; > + > + request->actual = 0; > + request->status = -EINPROGRESS; > + > + dev_dbg(&priv_dev->dev, "Queuing to endpoint: %s\n", priv_ep->name); > + > + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, > + usb_endpoint_dir_in(ep->desc)); > + > + if (ret) > + return ret; > + > + if (!cdns3_ep_run_transfer(priv_ep, request)) > + list_add_tail(&request->list, &priv_ep->request_list); how about catching the return value if cdns3_ep_run_transfer() fails? > + > + return ret; > +} > + > +static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct usb_request *zlp_request; > + unsigned long flags; > + int ret; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + ret = __cdns3_gadget_ep_queue(ep, request, gfp_flags); > + > + if (ret == 0 && request->zero && request->length && > + (request->length % ep->maxpacket == 0)) { > + zlp_request = cdns3_gadget_ep_alloc_request(ep, GFP_ATOMIC); > + zlp_request->buf = priv_dev->zlp_buf; > + zlp_request->length = 0; > + > + dev_dbg(&priv_dev->dev, "Queuing ZLP for endpoint: %s\n", > + priv_ep->name); > + ret = __cdns3_gadget_ep_queue(ep, zlp_request, gfp_flags); Who is going to free this zlp_request? > + } > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_dequeue Remove request from transfer queue > + * @ep: endpoint object associated with request > + * @request: request object > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, > + struct usb_request *request) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct usb_request *req, *req_temp; > + unsigned long flags; > + int ret = 0; > + > + if (!ep || !request || !ep->desc) > + return -EINVAL; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + dev_dbg(&priv_dev->dev, "Dequeue from %s\n", ep->name); > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + if (priv_dev->start_gadget) > + ret = cdns3_data_flush(priv_ep); > + > + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { > + if (request == req) { > + cdns3_gadget_giveback(priv_ep, > + to_cdns3_request(request), > + -ECONNRESET); > + break; > + } > + } > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint > + * @ep: endpoint object to set/clear stall on > + * @value: 1 for set stall, 0 for clear stall > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + unsigned long flags; > + int ret = 0; > + > + if (!(priv_ep->flags & EP_ENABLED)) > + return -EPERM; > + > + /* if actual transfer is pending defer setting stall on this endpoint */ > + if ((priv_ep->flags & EP_PENDING_REQUEST) && value) { > + priv_ep->flags |= EP_STALL; > + return 0; > + } > + > + dev_dbg(&priv_dev->dev, "Halt endpoint %s\n", priv_ep->name); > + > + spin_lock_irqsave(&priv_dev->lock, flags); How about grabbing the lock before checking for priv->ep->flags? > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + if (value) { > + cdns3_ep_stall_flush(priv_ep); > + } else { > + priv_ep->flags &= ~EP_WEDGE; > + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); > + > + /* wait for EPRST cleared */ > + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, > + EP_CMD_EPRST, 0, 100); if there was an error we shouldn't be clearing the EP_STALL right and leave the pending flag? > + priv_ep->flags &= ~EP_STALL; > + } > + > + priv_ep->flags &= ~EP_PENDING_REQUEST; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + > + return ret; > +} > + > +extern const struct usb_ep_ops cdns3_gadget_ep0_ops; > + > +static const struct usb_ep_ops cdns3_gadget_ep_ops = { > + .enable = cdns3_gadget_ep_enable, > + .disable = cdns3_gadget_ep_disable, > + .alloc_request = cdns3_gadget_ep_alloc_request, > + .free_request = cdns3_gadget_ep_free_request, > + .queue = cdns3_gadget_ep_queue, > + .dequeue = cdns3_gadget_ep_dequeue, > + .set_halt = cdns3_gadget_ep_set_halt, > + .set_wedge = cdns3_gadget_ep_set_wedge, > +}; > + > /** > * cdns3_gadget_get_frame Returns number of actual ITP frame > * @gadget: gadget object > @@ -365,8 +804,7 @@ static int cdns3_init_ep(struct cdns3_device *priv_dev) > usb_ep_set_maxpacket_limit(&priv_ep->endpoint, > ENDPOINT_MAX_PACKET_LIMIT); > priv_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS; > - //TODO: Add implementation of cdns3_gadget_ep_ops > - //priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > + priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > if (ep_dir) > priv_ep->endpoint.caps.dir_in = 1; > else > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 3b0d4d2e4831..a4be288b34cb 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1072,4 +1072,7 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask); > int cdns3_init_ep0(struct cdns3_device *priv_dev); > void cdns3_ep0_config(struct cdns3_device *priv_dev); > void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); > +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep); > +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value); > + > #endif /* __LINUX_CDNS3_GADGET */ > cheers, -roger -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04EA7C43441 for ; Wed, 28 Nov 2018 12:46:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A5E1820660 for ; Wed, 28 Nov 2018 12:46:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A5E1820660 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728381AbeK1XsA (ORCPT ); Wed, 28 Nov 2018 18:48:00 -0500 Received: from fllv0016.ext.ti.com ([198.47.19.142]:55198 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727811AbeK1Xr7 (ORCPT ); Wed, 28 Nov 2018 18:47:59 -0500 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id wASCkFkV082027; Wed, 28 Nov 2018 06:46:15 -0600 Received: from DLEE100.ent.ti.com (dlee100.ent.ti.com [157.170.170.30]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id wASCkF6I090022 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 28 Nov 2018 06:46:15 -0600 Received: from DLEE113.ent.ti.com (157.170.170.24) by DLEE100.ent.ti.com (157.170.170.30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Wed, 28 Nov 2018 06:46:15 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Wed, 28 Nov 2018 06:46:15 -0600 Received: from [192.168.2.6] (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id wASCkB2l023573; Wed, 28 Nov 2018 06:46:12 -0600 Subject: Re: [RFC PATCH v2 09/15] usb:cdns3: EpX operations part of the API To: Pawel Laszczak , References: <1542535751-16079-1-git-send-email-pawell@cadence.com> <1542535751-16079-10-git-send-email-pawell@cadence.com> CC: , , , , , , , , , , From: Roger Quadros Message-ID: <5BFE8E12.9080307@ti.com> Date: Wed, 28 Nov 2018 14:46:10 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: <1542535751-16079-10-git-send-email-pawell@cadence.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 18/11/18 12:09, Pawel Laszczak wrote: > Patch implements callback functions for non-default endpoints > defined in usb_ep_ops object. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/cdns3/ep0.c | 18 ++ > drivers/usb/cdns3/gadget.c | 442 ++++++++++++++++++++++++++++++++++++- > drivers/usb/cdns3/gadget.h | 3 + > 3 files changed, 461 insertions(+), 2 deletions(-) > > diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c > index c08d02665f9d..ca1795467155 100644 > --- a/drivers/usb/cdns3/ep0.c > +++ b/drivers/usb/cdns3/ep0.c > @@ -23,6 +23,24 @@ static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) > //TODO: Implements this function > } > > +/** > + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint > + * @ep: endpoint object > + * > + * Returns 0 > + */ > +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + dev_dbg(&priv_dev->dev, "Wedge for %s\n", ep->name); > + cdns3_gadget_ep_set_halt(ep, 1); > + priv_ep->flags |= EP_WEDGE; > + > + return 0; > +} > + > /** > * cdns3_ep0_config - Configures default endpoint > * @priv_dev: extended gadget object > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > index 702a05faa664..1f2a434486dc 100644 > --- a/drivers/usb/cdns3/gadget.c > +++ b/drivers/usb/cdns3/gadget.c > @@ -58,6 +58,19 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) > writel(mask, ptr); > } > > +/** > + * cdns3_next_request - returns next request from list > + * @list: list containing requests > + * > + * Returns request or NULL if no requests in list > + */ > +struct usb_request *cdns3_next_request(struct list_head *list) > +{ > + if (list_empty(list)) > + return NULL; > + return list_first_entry(list, struct usb_request, list); > +} > + > /** > * select_ep - selects endpoint > * @priv_dev: extended gadget object > @@ -73,6 +86,53 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) > writel(ep, &priv_dev->regs->ep_sel); > } > > +/** > + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint > + * @priv_ep: endpoint object > + * > + * Function will return 0 on success or -ENOMEM on allocation error > + */ > +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct cdns3_trb *link_trb; > + > + if (!priv_ep->trb_pool) { > + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, > + TRB_RIGN_SIZE, TRB_RING_SIZE > + &priv_ep->trb_pool_dma, > + GFP_DMA); > + if (!priv_ep->trb_pool) > + return -ENOMEM; > + } else { > + memset(priv_ep->trb_pool, 0, TRB_RIGN_SIZE); here too. > + } > + > + if (!priv_ep->aligned_buff) { > + priv_ep->aligned_buff = dma_alloc_coherent(priv_dev->sysdev, > + CDNS3_UNALIGNED_BUF_SIZE, CDNS3_ALIGNED_BUF_SIZE > + &priv_ep->aligned_dma_addr, > + GFP_DMA); > + if (!priv_ep->aligned_buff) { > + dma_free_coherent(priv_dev->sysdev, > + TRB_RIGN_SIZE, > + priv_ep->trb_pool, > + priv_ep->trb_pool_dma); > + priv_ep->trb_pool = NULL; > + > + return -ENOMEM; > + } > + } > + > + /* Initialize the last TRB as Link TRB */ > + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); > + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); > + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | > + TRB_CHAIN | TRB_TOGGLE; > + > + return 0; > +} > + > static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) > { > struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > @@ -92,6 +152,73 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) > } > } > > +/** > + * cdns3_data_flush - flush data at onchip buffer > + * @priv_ep: endpoint object > + * > + * Endpoint must be selected before call to this function > + * > + * Returns zero on success or negative value on failure > + */ > +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); > + > + /* wait for DFLUSH cleared */ > + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); > +} > + > +/** > + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint > + * @priv_ep: endpoint object > + * > + * Endpoint must be selected before call to this function > + */ > +static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) > +{ > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + > + writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL, > + &priv_dev->regs->ep_cmd); > + > + /* wait for DFLUSH cleared */ > + cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); > + priv_ep->flags |= EP_STALL; > +} > + > +/** > + * cdns3_gadget_giveback - call struct usb_request's ->complete callback > + * @priv_ep: The endpoint to whom the request belongs to > + * @priv_req: The request we're giving back > + * @status: completion code for the request > + * > + * Must be called with controller's lock held and interrupts disabled. This > + * function will unmap @req and call its ->complete() callback to notify upper > + * layers that it has completed. > + */ > +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, > + struct cdns3_request *priv_req, > + int status) > +{ > + //TODO: Implements this function. > +} > + > +/** > + * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware > + * @priv_ep: endpoint object > + * > + * Returns zero on success or negative value on failure > + */ > +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, > + struct usb_request *request) > +{ > + //TODO: Implements this function. > + > + return 0; > +} > + > /** > * cdns3_irq_handler - irq line interrupt handler > * @cdns: cdns3 instance > @@ -170,6 +297,318 @@ static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, > return &priv_ep->endpoint; > } > > +/** > + * cdns3_gadget_ep_enable Enable endpoint > + * @ep: endpoint object > + * @desc: endpoint descriptor > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_gadget_ep_enable(struct usb_ep *ep, > + const struct usb_endpoint_descriptor *desc) > +{ > + struct cdns3_endpoint *priv_ep; > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret; > + u32 reg; > + > + priv_ep = ep_to_cdns3_ep(ep); > + priv_dev = priv_ep->cdns3_dev; > + > + if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { > + dev_err(&priv_dev->dev, "usbss: invalid parameters\n"); dev_dbg()? Gadget driver will be more verbose. > + return -EINVAL; > + } > + > + if (!desc->wMaxPacketSize) { > + dev_err(&priv_dev->dev, "usbss: missing wMaxPacketSize\n"); > + return -EINVAL; > + } > + > + if (dev_WARN_ONCE(&priv_dev->dev, priv_ep->flags & EP_ENABLED, > + "%s is already enabled\n", priv_ep->name)) > + return 0; > + > + ret = cdns3_allocate_trb_pool(priv_ep); > + if (ret) > + return ret; Why not allocate the TRB pool once for all endpoints at gadget init? you don't seem to be calling cdns3_allocate_trb_pool() in cdns3_gadget_ep_disable(). > + > + dev_dbg(&priv_dev->dev, "Enabling endpoint: %s\n", ep->name); > + spin_lock_irqsave(&priv_dev->lock, flags); > + cdns3_select_ep(priv_dev, desc->bEndpointAddress); > + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); > + > + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, > + EP_CMD_CSTALL | EP_CMD_EPRST, 0, 100); > + > + cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE); > + > + ep->desc = desc; > + priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALL); > + priv_ep->flags |= EP_ENABLED | EP_UPDATE_EP_TRBADDR; > + priv_ep->enqueue = 0; > + priv_ep->dequeue = 0; > + reg = readl(&priv_dev->regs->ep_sts); > + priv_ep->pcs = !!EP_STS_CCS(reg); > + priv_ep->ccs = !!EP_STS_CCS(reg); > + /* one TRB is reserved for link TRB used in DMULT mode*/ > + priv_ep->free_trbs = TRBS_PER_SEGMENT - 1; > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_ep_disable Disable endpoint > + * @ep: endpoint object > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_gadget_ep_disable(struct usb_ep *ep) > +{ > + struct cdns3_endpoint *priv_ep; > + struct cdns3_device *priv_dev; > + unsigned long flags; > + int ret = 0; > + struct usb_request *request; > + u32 ep_cfg; > + > + if (!ep) { > + pr_debug("usbss: invalid parameters\n"); > + return -EINVAL; > + } > + > + priv_ep = ep_to_cdns3_ep(ep); > + priv_dev = priv_ep->cdns3_dev; > + > + if (dev_WARN_ONCE(&priv_dev->dev, !(priv_ep->flags & EP_ENABLED), > + "%s is already disabled\n", priv_ep->name)) > + return 0; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + if (!priv_dev->start_gadget) { > + dev_dbg(&priv_dev->dev, > + "Disabling endpoint at disconnection: %s\n", ep->name); This flag is looking very tricky. What do you mean by "disabling at disconnection"? > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; EP is not yet disabled and we're returning 0. This will cause an unbalance. I'd avoid that flag altogether. > + } > + > + dev_dbg(&priv_dev->dev, "Disabling endpoint: %s\n", ep->name); > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + ret = cdns3_data_flush(priv_ep); > + while (!list_empty(&priv_ep->request_list)) { > + request = cdns3_next_request(&priv_ep->request_list); > + > + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), > + -ESHUTDOWN); > + } > + > + ep_cfg = readl(&priv_dev->regs->ep_cfg); > + ep_cfg &= ~EP_CFG_ENABLE; > + writel(ep_cfg, &priv_dev->regs->ep_cfg); > + ep->desc = NULL; > + priv_ep->flags &= ~EP_ENABLED; > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_alloc_request Allocates request > + * @ep: endpoint object associated with request > + * @gfp_flags: gfp flags > + * > + * Returns allocated request address, NULL on allocation error > + */ > +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_request *priv_req; > + > + priv_req = kzalloc(sizeof(*priv_req), gfp_flags); > + if (!priv_req) > + return NULL; > + > + priv_req->priv_ep = priv_ep; > + > + return &priv_req->request; > +} > + > +/** > + * cdns3_gadget_ep_free_request Free memory occupied by request > + * @ep: endpoint object associated with request > + * @request: request to free memory > + */ > +void cdns3_gadget_ep_free_request(struct usb_ep *ep, > + struct usb_request *request) > +{ > + struct cdns3_request *priv_req = to_cdns3_request(request); > + > + kfree(priv_req); > +} > + > +/** > + * cdns3_gadget_ep_queue Transfer data on endpoint > + * @ep: endpoint object > + * @request: request object > + * @gfp_flags: gfp flags > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, > + struct usb_request *request, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + int ret = 0; > + > + request->actual = 0; > + request->status = -EINPROGRESS; > + > + dev_dbg(&priv_dev->dev, "Queuing to endpoint: %s\n", priv_ep->name); > + > + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, > + usb_endpoint_dir_in(ep->desc)); > + > + if (ret) > + return ret; > + > + if (!cdns3_ep_run_transfer(priv_ep, request)) > + list_add_tail(&request->list, &priv_ep->request_list); how about catching the return value if cdns3_ep_run_transfer() fails? > + > + return ret; > +} > + > +static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, > + gfp_t gfp_flags) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct usb_request *zlp_request; > + unsigned long flags; > + int ret; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + ret = __cdns3_gadget_ep_queue(ep, request, gfp_flags); > + > + if (ret == 0 && request->zero && request->length && > + (request->length % ep->maxpacket == 0)) { > + zlp_request = cdns3_gadget_ep_alloc_request(ep, GFP_ATOMIC); > + zlp_request->buf = priv_dev->zlp_buf; > + zlp_request->length = 0; > + > + dev_dbg(&priv_dev->dev, "Queuing ZLP for endpoint: %s\n", > + priv_ep->name); > + ret = __cdns3_gadget_ep_queue(ep, zlp_request, gfp_flags); Who is going to free this zlp_request? > + } > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_dequeue Remove request from transfer queue > + * @ep: endpoint object associated with request > + * @request: request object > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, > + struct usb_request *request) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + struct usb_request *req, *req_temp; > + unsigned long flags; > + int ret = 0; > + > + if (!ep || !request || !ep->desc) > + return -EINVAL; > + > + spin_lock_irqsave(&priv_dev->lock, flags); > + dev_dbg(&priv_dev->dev, "Dequeue from %s\n", ep->name); > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + if (priv_dev->start_gadget) > + ret = cdns3_data_flush(priv_ep); > + > + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { > + if (request == req) { > + cdns3_gadget_giveback(priv_ep, > + to_cdns3_request(request), > + -ECONNRESET); > + break; > + } > + } > + > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return ret; > +} > + > +/** > + * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint > + * @ep: endpoint object to set/clear stall on > + * @value: 1 for set stall, 0 for clear stall > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value) > +{ > + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); > + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > + unsigned long flags; > + int ret = 0; > + > + if (!(priv_ep->flags & EP_ENABLED)) > + return -EPERM; > + > + /* if actual transfer is pending defer setting stall on this endpoint */ > + if ((priv_ep->flags & EP_PENDING_REQUEST) && value) { > + priv_ep->flags |= EP_STALL; > + return 0; > + } > + > + dev_dbg(&priv_dev->dev, "Halt endpoint %s\n", priv_ep->name); > + > + spin_lock_irqsave(&priv_dev->lock, flags); How about grabbing the lock before checking for priv->ep->flags? > + > + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); > + if (value) { > + cdns3_ep_stall_flush(priv_ep); > + } else { > + priv_ep->flags &= ~EP_WEDGE; > + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); > + > + /* wait for EPRST cleared */ > + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, > + EP_CMD_EPRST, 0, 100); if there was an error we shouldn't be clearing the EP_STALL right and leave the pending flag? > + priv_ep->flags &= ~EP_STALL; > + } > + > + priv_ep->flags &= ~EP_PENDING_REQUEST; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + > + return ret; > +} > + > +extern const struct usb_ep_ops cdns3_gadget_ep0_ops; > + > +static const struct usb_ep_ops cdns3_gadget_ep_ops = { > + .enable = cdns3_gadget_ep_enable, > + .disable = cdns3_gadget_ep_disable, > + .alloc_request = cdns3_gadget_ep_alloc_request, > + .free_request = cdns3_gadget_ep_free_request, > + .queue = cdns3_gadget_ep_queue, > + .dequeue = cdns3_gadget_ep_dequeue, > + .set_halt = cdns3_gadget_ep_set_halt, > + .set_wedge = cdns3_gadget_ep_set_wedge, > +}; > + > /** > * cdns3_gadget_get_frame Returns number of actual ITP frame > * @gadget: gadget object > @@ -365,8 +804,7 @@ static int cdns3_init_ep(struct cdns3_device *priv_dev) > usb_ep_set_maxpacket_limit(&priv_ep->endpoint, > ENDPOINT_MAX_PACKET_LIMIT); > priv_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS; > - //TODO: Add implementation of cdns3_gadget_ep_ops > - //priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > + priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > if (ep_dir) > priv_ep->endpoint.caps.dir_in = 1; > else > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 3b0d4d2e4831..a4be288b34cb 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1072,4 +1072,7 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask); > int cdns3_init_ep0(struct cdns3_device *priv_dev); > void cdns3_ep0_config(struct cdns3_device *priv_dev); > void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); > +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep); > +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value); > + > #endif /* __LINUX_CDNS3_GADGET */ > cheers, -roger -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki