Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756805AbcJWW1A (ORCPT ); Sun, 23 Oct 2016 18:27:00 -0400 Received: from mail-db5eur01on0116.outbound.protection.outlook.com ([104.47.2.116]:51279 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754380AbcJWW0z (ORCPT ); Sun, 23 Oct 2016 18:26:55 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; Subject: Re: [PATCH v2 1/7] iio:core: add a callback to allow drivers to provide _available attributes To: Jonathan Cameron , References: <1477176226-10566-1-git-send-email-peda@axentia.se> <1477176226-10566-2-git-send-email-peda@axentia.se> <74746223-a1aa-e9c6-622c-854526d0722d@kernel.org> CC: Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Rob Herring , Mark Rutland , , From: Peter Rosin Organization: Axentia Technologies AB Message-ID: <6a079aa4-f56e-1090-924e-aa3911ce0fca@axentia.se> Date: Mon, 24 Oct 2016 00:10:43 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <74746223-a1aa-e9c6-622c-854526d0722d@kernel.org> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: DB5PR08CA0070.eurprd08.prod.outlook.com (10.166.166.166) To AM5PR0201MB2307.eurprd02.prod.outlook.com (10.169.242.151) X-MS-Office365-Filtering-Correlation-Id: 6b1fd15f-656a-467e-9851-08d3fb91720f X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2307;2:EdK1/xi2MhYXzu3qXvQPDH0JCCY/7mM6Qn/CfVapdzDG0TIJD6TcBoub6bYxyAyRdvsoMg3CuhXVJ3tt+1l7LQMH+jM04LAeajunAhNLWIZ3EvGz0JH9siGcpkC4C+L5HeOtRY1KrH79ep22dvzAWHwjcO7IRa0ZMQOaaJA6KEc+gNA7Eq5mThzMecpGPIJ8MevGUsoC1oxz16KGQFgFAA==;3:QHxNC4A6gClG8jX8bUlQi1biwZIotlqc4C30Uq8iPLjsfiFg03Dq28ZC5G2TUsEE4TyW37opu8TSKHlBzAgy/jbvodl0/R4vAQMPYKBnoEsyCV6IMI/pMZBFGvD10z4mRHOr4bkK/C4Sco2oNoufYg== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:AM5PR0201MB2307; X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2307;25:FnsQiPe5RUWGjCOcjVSCxCY3i6AON7W7wRgwqRrYOIeAMbChhKy1RH+ZfgrajIISjLu3BLuOdEHCt4qiM/Z0bj5jf0uirZmNDsHpv/J6OViSAKZVD1YNi02Uk2MmAOAQmla51B201TeEHYAojx/OQaFU891ledgjrP0dWka9QaSKtwwb1Ro8d8h2CbsIXXvoPwfwHAv6Q3Fh6yeAze6wVGiON8it76xRyLAIbSdHxB4X7j/L22Z/rvjPeQNy9PSDH0AqeOtsV4LGwnuCvNS79Om1ImV5IGRA9mmjxUUzW5+AtMXw4PASx615dkiOf902QD/sK/bHcQOA4fi0slsLn0J5pbkaOvsQIHZfjw+/lUSXG/5vJDTdZTvlxfIVKEVZ059LuI/3kPKwZrEFsf81ahkfhkZDf/KHgkMYKAhNLhp80sG/eeWyE61MJeBp3nvrV71BX0qwe1sQKdVHcvVWo7J7MPerYgTeCZd0FxpVXf+4ep6Ry7zZpPD0oaUOcjOPHdkb6ch8hM8pDpCTYfwietMkqquqX9KzhJ9zuX6OgzjOBL8Od2zBPfvGFfQaCOAMmrOZDbeIGa2uNoyf8tlAtWWO8BGo6yttoXD01tPV9+iVi1NUdwJGykH/EN/UeaEHNtDha9EfHYwA/DXBLpZBWX+hzhebNKvypba+NK1XuFt2VInxxpvbM5XItfhBemJLF2aAj+ceuIiEzsYSWoNt0LSm1hRBx0R+7XMRTszL7bE= X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2307;31:tAe4y5XuFVx2aI/PFzh2uADb1TOC0BaDhkalMCpDDcwAatUgkmX9UtRat1w6YqHBleEZ5lLlQN82TmH2mCDNPiymsFyHXVngEFf/o7p+BbqALU8sf4Eh9mQ6V1p99+JpWdJ7YjY6cy440Mbv58f0e04c4hxNOBTdzgVc5lHOtXsl6zCrY8e9DpZIfFAGsDz+5p2YGFVMinxfddDl1HoiKCHn2ga/30we1sGqWQ/8NBgsxFqSfkI1xXhgdyTWEYwq;4:uGIo4FDfwLQhXYXwQP7pm7NB+mNThEG+tN7cLoutLIBqOAY5G8TK9f2ZbPqRljVOFXMK+2/yYjRKr6Bm61oKpNg5GcsOUH6ZYPfBzR8bO1OiI23m+2fnDjOIGLxpOPTt7sOKyRj00FIgj0WNrRgiYzb+7/0oLnOpYOg7RBIGihOvIcVefyGjd4QpCp4QYkKc6rpK3lSVsRqBoqLLnRw0m8vSSiis3Ha3UDllJhNhip3iL1kb2z8Pmz4w9vON1YHlUONJ7GMTQxrV8kZ9KHkr/gu/1IiZFBhwlIV0GpK/5roFi2giWnvw1z7KT7B+0St/0ePmZN2s7XW8JbchqjsMLH8Jr4uChgOuJGQwaBnq9bYR/Nvj7KQXiGCLs18u00z26usK+Asy/ZlbOdKFC5b4RYm8NmJKveHFI9q1IiZAUcgPfuQ3mBze+cnOfLaqUM1G X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6043046)(6042046);SRVR:AM5PR0201MB2307;BCL:0;PCL:0;RULEID:;SRVR:AM5PR0201MB2307; X-Forefront-PRVS: 0104247462 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(6049001)(7916002)(199003)(24454002)(377424004)(52544003)(43784003)(189002)(19580395003)(50466002)(19580405001)(117156001)(23746002)(5001770100001)(101416001)(586003)(7736002)(4326007)(230700001)(7846002)(74482002)(97736004)(8666005)(3846002)(6116002)(36756003)(189998001)(81166006)(105586002)(81156014)(106356001)(2950100002)(8676002)(83506001)(64126003)(305945005)(92566002)(77096005)(68736007)(6666003)(2906002)(86362001)(575784001)(42186005)(31686004)(33646002)(65826007)(47776003)(31696002)(4001150100001)(50986999)(66066001)(54356999)(76176999)(65806001)(5660300001)(4001350100001)(65956001)(7059030)(42262002);DIR:OUT;SFP:1102;SCL:1;SRVR:AM5PR0201MB2307;H:[192.168.0.125];FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?Windows-1252?Q?1;AM5PR0201MB2307;23:WBSLRDeFDLvAwRqlyh2/a2VJhkJyIcLQy2j?= =?Windows-1252?Q?jr9BG7+8Ac2vTQr3eZX6fzx8gG8m+vrGqphZLJ17wjnr40ZjGN4JHG+f?= =?Windows-1252?Q?gb/IdTPuj/Bw/i/4KD3VvhE3fyDxXisjI7xGF2EB+BZnOwX8W7iwhPEb?= =?Windows-1252?Q?M5oLXxStlXoj65UkkDOZbX55DN7qsxtL78WvWjMOZAo7uH3HZRk0qZph?= =?Windows-1252?Q?Etm1UqA5dbPpdQUK73XjZOMaGTYvG18PgSsbs0NK8yr9T5gZepW8E5o5?= =?Windows-1252?Q?NXpqFmrbqevDCvttDhgBFSJwJ5++Ysr1UvMGZmPS0vqk0Cxye90+CY35?= =?Windows-1252?Q?5YQAZIvbYajW5vd5loSfnXmZZ46GGK4P7BXOEniW5HTBwhpU09SqMfW6?= =?Windows-1252?Q?Be8RLPr+f5lBiEUJPnBaJ2Znluii0oaXl1KEszGmhRahs/NIjWO/iifb?= =?Windows-1252?Q?hzNwdIBebtR5pXAMWJuai7vOQvOuRQ44kDdKQ7ctApNJsqDGUL2Bmp+M?= =?Windows-1252?Q?EsFI6Q10461WA5bA6wCR9VCoWm7la9K2K6r0vdKT3FZWlp19cKyPOPIE?= =?Windows-1252?Q?Zn151Lz2ItIMfpG5q2pukqgmyiOcKO2JzzRjXAK17S3/IhPqFFvoLLoD?= =?Windows-1252?Q?M+E4fHUrtLRqM9NOHpE3GvUzv2eqJWlcrCUFTktfyMGcI0qiGYbGN1ov?= =?Windows-1252?Q?7vK8cSNH8KxfmtSlYPwcQUbcM8I+4nyObnwjqbA+XLWBmSh/fF39cNG+?= =?Windows-1252?Q?rVmdcj1cW4EW0KggkRNOMDOfQsO0Tsbv+29PeLGqy3mhxGZNLvXO8eMF?= =?Windows-1252?Q?KlS7Ahzmp73j0gmlwrI9gjkPEZiWdrGKhPm3gPPc64bcPBnzTu4ydMig?= =?Windows-1252?Q?2l/LAYqyv3lwGiBU8zcWX+/4aqiafjDE58e3O7iXKAL2V3c03xro14xq?= =?Windows-1252?Q?zfeDbNBox+NbxHPcENM0TiO06IGAZwk2+y0W9SrGIc8nZZnq4mDAEIn1?= =?Windows-1252?Q?t33NwWigrE/6IzgP4m41gFJW2MSuK8YEOTi3+66cmJBt01xqRPXH8FyN?= =?Windows-1252?Q?TaCB9mjfTjC0I0N9Al5rjPbY9TsdbYQFAyenT7j0NMt+ZzLyO41hobm6?= =?Windows-1252?Q?wu2p2ttg1yo/g5SECA/1LLFvlCqCMgNRTC8xM2KFi6w5QnBmuhHO1oaP?= =?Windows-1252?Q?NyCFnwOb0Kqp5alpj+efOr3tkYTf/NJPCmdNVp7lzEvjzwLeJS1210MC?= =?Windows-1252?Q?C1V1HvS0Z68f3qktS1nXMTGfKRlmYV4GQV27JJbLTGNGE8KkNCQx3HkR?= =?Windows-1252?Q?h4c/j2AHTt4vamjWIT4ceDF1suNbynjDZI1sxXryOScdJ1CDf146Qzk7?= =?Windows-1252?Q?HOx0/gO1EzCzWXqDgLImwh1EOAWST4leKd2+NbMDF/QgpIXsUY7AfxL3?= =?Windows-1252?Q?DU1PWoOdf7eDifwzy7Y6WPfDJSDgKqppXJiKbyLYvpmOiGrOP/xb7PN/?= =?Windows-1252?Q?guhI+JOLxkAT9Wq0pxBwRPs7QeI3Me3BpIq56AmYFpCSUWvtG6J215GC?= =?Windows-1252?Q?zLtWRAQ+tPpZnmoQI2IHvsat2zb3whE36BC8eD0F0ayGSlcTSnsZi6Cx?= =?Windows-1252?Q?5Aw=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2307;6:OFqNT7XkMkFQIY7hJJ13MHS9RjBghA42TkdsgjqMtxSnd0ZRaP5cJoZ+tgWerKDBt8FfEigDjM/AGJtwk+x/A97K8zlCQ0U9ZWGgzGGYIvZBokG3lQrnfdjQIbD+f3rfdprOnsPWxAmCelCT1nMZ5jBbqkpxeIkrulzw7vHBYD+z0UA/Z5crfj7FY0xX8bZL92YCDbcRv1K4945exAXXZpMTF60eClHIjlq6ymYTxfFtmtchxJGL9aYUoNMoCarPAoJ5lPguB110CnPbvb1Dx4U+UqBdOCK8G5gtOE5b+u0zJPjzLmTq6VyTBsElR9+S7U/rpbLhhrpyGwABcWxZBA==;5:lDg6j9H1T7LBX7748jGc7MHYLheqBG6AgeHPKGPWXnFuDWVcvPad1uEUUPucIDpeGlJRBTGL/s/Gc46Ni7afzox7nFPUxu1/+9swtzo3zXlsBYyY02ouEkp9W/9jjZZfSYZy+TSPpv9qyQfmvM8mXg==;24:BUbocBtY5tCdQvzdFmu+fcYAGBqEnNxDXNObLE3SzS2zpl0SMUcAMSQ2fIjdR6JGKV6+EtcJDSdG1CuTOHV+5gObCr8tXIxtGMf6nhazWbk= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2307;7:+5ZY6tJK6vBx77LBAwAIpAR91RxXO+BIG/k0JRPn14bMTbXrSSDzxCLchjdrSsT8oCXEjGeVtYRd8VLSdGOaHgEI8cCxgkM4uhBdBLmL6BZtOry3fMQT/oLwf+ui5yRbwd/X1pAs6DqBZAAKqR8NgvLc4ck8qXcWes+ItV5LkJaosqhvymrhQ5gYFd/A8FRxz+gLIjbvvZ9YGiaPgoxouqtU1pVmQJ18fXWDELblNe8mggVFEzmN8ah9XIqv/Edl77t/SwyWz42fWJJSuzeQKNENP8rJwK6eeNUODpWlfa6hU6kjDFC4+24YjIJhV0i8tyi63s+Kkoe7mmefOWYaB33u9yptDHzk6490eeXXB5Q= X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Oct 2016 22:10:47.9666 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5PR0201MB2307 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 15025 Lines: 457 On 2016-10-23 11:33, Jonathan Cameron wrote: > On 22/10/16 23:43, Peter Rosin wrote: >> From: Jonathan Cameron >> >> A large number of attributes can only take a limited range of values. >> Currently in IIO this is handled by directly registering additional >> *_available attributes thus providing this information to userspace. >> >> It is desirable to provide this information via the core for much the same >> reason this was done for the actual channel information attributes in the >> first place. If it isn't there, then it can only really be accessed from >> userspace. Other in kernel IIO consumers have no access to what valid >> parameters are. >> >> Two forms are currently supported: >> * list of values in one particular IIO_VAL_* format. >> e.g. 1.300000 1.500000 1.730000 >> * range specification with a step size: >> e.g. [1.000000 0.500000 2.500000] >> equivalent to 1.000000 1.5000000 2.000000 2.500000 >> >> An addition set of masks are used to allow different sharing rules for the >> *_available attributes generated. >> >> This allows for example: >> >> in_accel_x_offset >> in_accel_y_offset >> in_accel_offset_available. >> >> We could have gone with having a specification for each and every >> info_mask element but that would have meant changing the existing userspace >> ABI. This approach does not. > I'm wondering what I meant by this... where does it cause use ABI issues? > Do you have any idea? Nope, sorry. My memory is probably just as blank as yours :-) > I'd forgotten I'd even done it like this rather than just insisting on > available for everything (which is more logical to me as we should know > the range of everything). > > It's pretty low cost though and gives a way of adding this to drivers > piecemeal which is probably a good idea! Yes, that's always a good sign. Flag days are a pain. >> Signed-off-by: Jonathan Cameron >> [rather mindlessly forward ported from approx 3 years ago /peda] > More importantly shepherding it through review! > > Naturally it's perfect code so not comments inline ;) > > Thanks again for picking this up! > > So... I want to see lots of comments on this. If people are happy with > it (unlikely ;) then please say so. It's at least a bit controversial Hmmm, maybe I should looking over the changes line-by-line, see inline comments... > and adds a 'lot' of new ABI. I'd appreciate it if someone else wrote up the common stuff in the testing/sysfs-bus/iio file. That file is a jungle to a newcomer... > Jonathan >> Signed-off-by: Peter Rosin >> --- >> drivers/iio/industrialio-core.c | 232 +++++++++++++++++++++++++++++++++++----- >> include/linux/iio/iio.h | 11 ++ >> include/linux/iio/types.h | 5 + >> 3 files changed, 223 insertions(+), 25 deletions(-) >> >> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c >> index fc340ed3dca1..93c69ebeda1e 100644 >> --- a/drivers/iio/industrialio-core.c >> +++ b/drivers/iio/industrialio-core.c >> @@ -575,51 +575,41 @@ int of_iio_read_mount_matrix(const struct device *dev, >> #endif >> EXPORT_SYMBOL(of_iio_read_mount_matrix); >> >> -/** >> - * iio_format_value() - Formats a IIO value into its string representation >> - * @buf: The buffer to which the formatted value gets written >> - * @type: One of the IIO_VAL_... constants. This decides how the val >> - * and val2 parameters are formatted. >> - * @size: Number of IIO value entries contained in vals >> - * @vals: Pointer to the values, exact meaning depends on the >> - * type parameter. >> - * >> - * Return: 0 by default, a negative number on failure or the >> - * total number of characters written for a type that belongs >> - * to the IIO_VAL_... constant. >> - */ >> -ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) >> +static ssize_t __iio_format_value(char *buf, unsigned int type, >> + int size, const int *vals) >> { >> unsigned long long tmp; >> + int tmp0, tmp1; >> bool scale_db = false; >> >> switch (type) { >> case IIO_VAL_INT: >> - return sprintf(buf, "%d\n", vals[0]); >> + return sprintf(buf, "%d", vals[0]); This function was previously used to format one or a perhaps a few values presumable at the start of a page. It doesn't bother to check for buffer overflow. That is probably very bad now that it is used to print arbitrary length lists of values... I'll add a suggested fix in v3. >> case IIO_VAL_INT_PLUS_MICRO_DB: >> scale_db = true; >> case IIO_VAL_INT_PLUS_MICRO: >> if (vals[1] < 0) >> - return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]), >> + return sprintf(buf, "-%d.%06u%s", abs(vals[0]), >> -vals[1], scale_db ? " dB" : ""); >> else >> - return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1], >> + return sprintf(buf, "%d.%06u%s", vals[0], vals[1], >> scale_db ? " dB" : ""); >> case IIO_VAL_INT_PLUS_NANO: >> if (vals[1] < 0) >> - return sprintf(buf, "-%d.%09u\n", abs(vals[0]), >> + return sprintf(buf, "-%d.%09u", abs(vals[0]), >> -vals[1]); >> else >> - return sprintf(buf, "%d.%09u\n", vals[0], vals[1]); >> + return sprintf(buf, "%d.%09u", vals[0], vals[1]); >> case IIO_VAL_FRACTIONAL: >> tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]); >> - vals[0] = (int)div_s64_rem(tmp, 1000000000, &vals[1]); >> - return sprintf(buf, "%d.%09u\n", vals[0], abs(vals[1])); >> + tmp1 = vals[1]; >> + tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1); >> + return sprintf(buf, "%d.%09u", tmp0, abs(tmp1)); >> case IIO_VAL_FRACTIONAL_LOG2: >> tmp = (s64)vals[0] * 1000000000LL >> vals[1]; >> - vals[1] = do_div(tmp, 1000000000LL); >> - vals[0] = tmp; >> - return sprintf(buf, "%d.%09u\n", vals[0], vals[1]); >> + tmp1 = do_div(tmp, 1000000000LL); >> + tmp0 = tmp; >> + return sprintf(buf, "%d.%09u", tmp0, tmp1); >> case IIO_VAL_INT_MULTIPLE: >> { >> int i; >> @@ -628,13 +618,34 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) >> for (i = 0; i < size; ++i) >> len += snprintf(&buf[len], PAGE_SIZE - len, "%d ", >> vals[i]); This seems like a dangerous thing to do, arg 2 of snprintf is size_t which is unsigned, so if one call would have overflowed the buffer, the next will see a negative available buffer, turned very large since unsigned. *boom* I'll add a suggested fix in v3. >> - len += snprintf(&buf[len], PAGE_SIZE - len, "\n"); >> return len; >> } >> default: >> return 0; >> } >> } >> + >> +/** >> + * iio_format_value() - Formats a IIO value into its string representation >> + * @buf: The buffer to which the formatted value gets written >> + * @type: One of the IIO_VAL_... constants. This decides how the val >> + * and val2 parameters are formatted. >> + * @size: Number of IIO value entries contained in vals >> + * @vals: Pointer to the values, exact meaning depends on the >> + * type parameter. >> + * >> + * Return: 0 by default, a negative number on failure or the >> + * total number of characters written for a type that belongs >> + * to the IIO_VAL_... constant. >> + */ >> +ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) >> +{ >> + ssize_t len; >> + >> + len = __iio_format_value(buf, type, size, vals); >> + >> + return len + sprintf(buf + len, "\n"); >> +} >> EXPORT_SYMBOL_GPL(iio_format_value); >> >> static ssize_t iio_read_channel_info(struct device *dev, >> @@ -662,6 +673,113 @@ static ssize_t iio_read_channel_info(struct device *dev, >> return iio_format_value(buf, ret, val_len, vals); >> } >> >> +static ssize_t iio_format_avail_list(char *buf, const int *vals, >> + int type, int length) >> +{ >> + int i; >> + ssize_t len = 0; >> + >> + switch (type) { >> + case IIO_VAL_INT: >> + for (i = 0; i < length; i++) { >> + len += __iio_format_value(buf + len, type, 1, &vals[i]); >> + if (i < length - 1) >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + " "); >> + else >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + "\n"); >> + } >> + break; >> + default: >> + for (i = 0; i < length / 2; i++) { >> + len += __iio_format_value(buf + len, >> + type, >> + 2, >> + &vals[i * 2]); >> + if (i < length / 2 - 1) >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + " "); >> + else >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + "\n"); >> + } >> + }; >> + >> + return len; >> +} >> + >> +static ssize_t iio_format_avail_range(char *buf, const int *vals, int type) >> +{ >> + int i; >> + ssize_t len; >> + >> + len = snprintf(buf, PAGE_SIZE, "["); >> + switch (type) { >> + case IIO_VAL_INT: >> + for (i = 0; i < 3; i++) { >> + len += __iio_format_value(buf + len, type, 1, &vals[i]); >> + if (i < 2) >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + " "); >> + else >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + "]\n"); >> + } >> + break; >> + default: >> + for (i = 0; i < 3; i++) { >> + len += __iio_format_value(buf + len, >> + type, >> + 2, >> + &vals[i * 2]); >> + if (i < 2) >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + " "); >> + else >> + len += snprintf(buf + len, >> + PAGE_SIZE - len, >> + "]\n"); >> + } >> + }; >> + >> + return len; >> +} >> + >> +static ssize_t iio_read_channel_info_avail(struct device *dev, >> + struct device_attribute *attr, >> + char *buf) >> +{ >> + struct iio_dev *indio_dev = dev_to_iio_dev(dev); >> + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); >> + const int *vals; >> + int ret; >> + int length; >> + int type; >> + >> + ret = indio_dev->info->read_avail(indio_dev, this_attr->c, >> + &vals, &type, &length, >> + this_attr->address); >> + >> + if (ret < 0) >> + return ret; >> + switch (ret) { >> + case IIO_AVAIL_LIST: >> + return iio_format_avail_list(buf, vals, type, length); >> + case IIO_AVAIL_RANGE: >> + return iio_format_avail_range(buf, vals, type); >> + default: >> + return -EINVAL; >> + } >> +} >> + >> /** >> * iio_str_to_fixpoint() - Parse a fixed-point number from a string >> * @str: The string to parse >> @@ -978,6 +1096,40 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, >> return attrcount; >> } >> >> +static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, >> + struct iio_chan_spec const *chan, >> + enum iio_shared_by shared_by, >> + const long *infomask) >> +{ >> + int i, ret, attrcount = 0; >> + char *avail_postfix; >> + >> + for_each_set_bit(i, infomask, sizeof(infomask) * 8) { >> + avail_postfix = kasprintf(GFP_KERNEL, >> + "%s_available", >> + iio_chan_info_postfix[i]); >> + if (!avail_postfix) >> + return -ENOMEM; >> + >> + ret = __iio_add_chan_devattr(avail_postfix, >> + chan, >> + &iio_read_channel_info_avail, >> + NULL, >> + i, >> + shared_by, >> + &indio_dev->dev, >> + &indio_dev->channel_attr_list); >> + kfree(avail_postfix); >> + if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) >> + continue; >> + else if (ret < 0) >> + return ret; >> + attrcount++; >> + } >> + >> + return attrcount; >> +} >> + >> static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, >> struct iio_chan_spec const *chan) >> { >> @@ -993,6 +1145,14 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, >> return ret; >> attrcount += ret; >> >> + ret = iio_device_add_info_mask_type_avail(indio_dev, chan, >> + IIO_SEPARATE, >> + &chan-> >> + info_mask_separate_available); >> + if (ret < 0) >> + return ret; >> + attrcount += ret; >> + >> ret = iio_device_add_info_mask_type(indio_dev, chan, >> IIO_SHARED_BY_TYPE, >> &chan->info_mask_shared_by_type); >> @@ -1000,6 +1160,14 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, >> return ret; >> attrcount += ret; >> >> + ret = iio_device_add_info_mask_type_avail(indio_dev, chan, >> + IIO_SHARED_BY_TYPE, >> + &chan-> >> + info_mask_shared_by_type_available); >> + if (ret < 0) >> + return ret; >> + attrcount += ret; >> + >> ret = iio_device_add_info_mask_type(indio_dev, chan, >> IIO_SHARED_BY_DIR, >> &chan->info_mask_shared_by_dir); >> @@ -1007,6 +1175,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, >> return ret; >> attrcount += ret; >> >> + ret = iio_device_add_info_mask_type_avail(indio_dev, chan, >> + IIO_SHARED_BY_DIR, >> + &chan->info_mask_shared_by_dir_available); >> + if (ret < 0) >> + return ret; >> + attrcount += ret; >> + >> ret = iio_device_add_info_mask_type(indio_dev, chan, >> IIO_SHARED_BY_ALL, >> &chan->info_mask_shared_by_all); >> @@ -1014,6 +1189,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, >> return ret; >> attrcount += ret; >> >> + ret = iio_device_add_info_mask_type_avail(indio_dev, chan, >> + IIO_SHARED_BY_ALL, >> + &chan->info_mask_shared_by_all_available); >> + if (ret < 0) >> + return ret; >> + attrcount += ret; >> + >> if (chan->ext_info) { >> unsigned int i = 0; >> for (ext_info = chan->ext_info; ext_info->name; ext_info++) { >> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h >> index b4a0679e4a49..c0f897084620 100644 >> --- a/include/linux/iio/iio.h >> +++ b/include/linux/iio/iio.h >> @@ -269,9 +269,13 @@ struct iio_chan_spec { >> enum iio_endian endianness; >> } scan_type; >> long info_mask_separate; >> + long info_mask_separate_available; >> long info_mask_shared_by_type; >> + long info_mask_shared_by_type_available; >> long info_mask_shared_by_dir; >> + long info_mask_shared_by_dir_available; >> long info_mask_shared_by_all; >> + long info_mask_shared_by_all_available; >> const struct iio_event_spec *event_spec; >> unsigned int num_event_specs; >> const struct iio_chan_spec_ext_info *ext_info; >> @@ -397,6 +401,13 @@ struct iio_info { >> int *val_len, >> long mask); >> >> + int (*read_avail)(struct iio_dev *indio_dev, >> + struct iio_chan_spec const *chan, >> + const int **vals, >> + int *type, >> + int *length, >> + long mask_el); >> + >> int (*write_raw)(struct iio_dev *indio_dev, >> struct iio_chan_spec const *chan, >> int val, >> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h >> index 32b579525004..2aa7b6384d64 100644 >> --- a/include/linux/iio/types.h >> +++ b/include/linux/iio/types.h >> @@ -29,4 +29,9 @@ enum iio_event_info { >> #define IIO_VAL_FRACTIONAL 10 >> #define IIO_VAL_FRACTIONAL_LOG2 11 >> >> +enum iio_available_type { >> + IIO_AVAIL_LIST, >> + IIO_AVAIL_RANGE, >> +}; >> + >> #endif /* _IIO_TYPES_H_ */ >> >