* Re: IIO ring buffer [not found] <0F1B54C89D5F954D8535DB252AF412FA05A222FC@chinexm1.ad.analog.com> @ 2010-02-22 11:16 ` Jonathan Cameron 2010-02-23 4:11 ` Song, Barry 2010-06-02 8:01 ` [Uclinux-dist-devel] " Barry Song 0 siblings, 2 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-02-22 11:16 UTC (permalink / raw) To: Song, Barry; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio Hi All, Just for reference as I'll be doing a proper announcement later. We now have linux-iio@vger.kernel.org as a mailing list for the project. Unless others have tracked it down it currently only has me as a member though and I'm waiting for confirmation from marc.info of an archive. > Hi Jonathan, > Now users depend on iio ring events(IIO_EVENT_CODE_RING_50/75/100_FULL) > to read data: > read_size = fread(&dat, 1, sizeof(struct > iio_event_data), > fp_ev); > switch (dat.id) { > case IIO_EVENT_CODE_RING_100_FULL: > toread = RingLength; > break; > case IIO_EVENT_CODE_RING_75_FULL: > toread = RingLength*3/4; > break; > case IIO_EVENT_CODE_RING_50_FULL: > toread = RingLength/2; > break; > default: > printf("Unexpecteded event code\n"); > continue; > } > read_size = read(fp, > data, > toread*size_from_scanmode(NumVals, > scan_ts)); > if (read_size == -EAGAIN) { > printf("nothing available \n"); > continue; > } > And iio ring access node doesn't support blocking io too. It seems we > lost to let users read data once ring is not empty. And some users maybe > not care about iio ring events at all, but just want to read data like a > input or audio driver. So how about adding the following support in iio > ring: > 1. add NOT EMPTY event in IIO event nodes Not keen. It might lead to a storm of events (at least it might in a cleverer ring buffer implementation or during a blocking read). Actually in this particular case it probably wouldn't do any harm. > 2. add blocking io support in read function of IIO access nodes That I agree would be a good idea. If we support poll/select on the buffer access chrdev then we will get the same effect per having a not empty event and cleaner semantics for anyone not interested in the other events. Not to mention I expect we will soon have alternative ring buffer implementations that don't supply any events at all and hence don't event have the relevant chrdev. As things are, you can quite happily read whenever you like. Now you mention it, that example code is somewhat missleading! The issue with this ring buffer implementation is the handling of a true blocking read is complex as at any given time you aren't guaranteed to get what you asked for even if it was there when you started the read. It should be possible to work around that though. It's possible this functionality might be better added to an alternative ring buffer implementation. Be vary wary of that ring implementation in general! I am and I wrote it. > If you agree with that, I can begin to add these and send you a patch. > And a problem I don't know is what you and other people have changed to > Greg's staging tree, and I am not sure what tree the patch should be > againest. Nothing has changed in this region of the code. In fact I think all that has gone into Greg's tree is a clean up patch form Mark Brown making a few functions static. Right now I'm still getting the max1363 driver into a state where it will be possible to do the ABI changes. > > For long term plan, is it possible for ring common level to handle more > common work to avoid code repeating in different drivers? I'm certainly happy for that to be the case if it becomes apparent which functionality is shared. I haven't seen any substantial cases as yet, but then I may well be missing things so feel free to submit suggestions (or as ever the better option of patches). Thanks, Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: IIO ring buffer 2010-02-22 11:16 ` IIO ring buffer Jonathan Cameron @ 2010-02-23 4:11 ` Song, Barry 2010-02-23 11:44 ` Jonathan Cameron 2010-06-02 8:01 ` [Uclinux-dist-devel] " Barry Song 1 sibling, 1 reply; 31+ messages in thread From: Song, Barry @ 2010-02-23 4:11 UTC (permalink / raw) To: Jonathan Cameron; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio =20 >-----Original Message----- >From: Jonathan Cameron [mailto:jic23@cam.ac.uk]=20 >Sent: Monday, February 22, 2010 7:17 PM >To: Song, Barry >Cc: jic23@hermes.cam.ac.uk; manuel.stahl@iis.fraunhofer.de;=20 >uclinux-dist-devel@blackfin.uclinux.org; linux-iio@vger.kernel.org >Subject: Re: IIO ring buffer > >Hi All, > >Just for reference as I'll be doing a proper announcement later. >We now have linux-iio@vger.kernel.org as a mailing list for=20 >the project. That's great. Lucky to become the 2nd member. >Unless others have tracked it down it currently only has me as a member >though and I'm waiting for confirmation from marc.info of an archive. > >> Hi Jonathan, >> Now users depend on iio ring=20 >events(IIO_EVENT_CODE_RING_50/75/100_FULL) >> to read data: >> read_size =3D fread(&dat, 1, sizeof(struct >> iio_event_data), >> fp_ev); >> switch (dat.id) { >> case IIO_EVENT_CODE_RING_100_FULL: >> toread =3D RingLength; >> break; >> case IIO_EVENT_CODE_RING_75_FULL: >> toread =3D RingLength*3/4; >> break; >> case IIO_EVENT_CODE_RING_50_FULL: >> toread =3D RingLength/2; >> break; >> default: >> printf("Unexpecteded event code\n"); >> continue; >> } =20 >> read_size =3D read(fp, >> data, >> toread*size_from_scanmode(NumVals, >> scan_ts)); >> if (read_size =3D=3D -EAGAIN) { >> printf("nothing available \n"); >> continue; >> } =20 >> And iio ring access node doesn't support blocking io too. =20 >It seems we >> lost to let users read data once ring is not empty. And some=20 >users maybe >> not care about iio ring events at all, but just want to read=20 >data like a >> input or audio driver. So how about adding the following=20 >support in iio >> ring: >> 1. add NOT EMPTY event in IIO event nodes >Not keen. It might lead to a storm of events (at least it might in a=20 >cleverer ring buffer implementation or during a blocking=20 >read). Actually >in this particular case it probably wouldn't do any harm. >> 2. add blocking io support in read function of IIO access nodes >That I agree would be a good idea. If we support poll/select=20 >on the buffer access >chrdev then we will get the same effect per having a not empty=20 >event and cleaner >semantics for anyone not interested in the other events. Not=20 >to mention I expect >we will soon have alternative ring buffer implementations that=20 >don't supply any >events at all and hence don't event have the relevant chrdev. That means 50%, 75%, 100% event will disappear and the ring event node will disappear too? =20 In fact, I doesn't understand the original purpose for those events. To support HW ring buffer notification to users? > >As things are, you can quite happily read whenever you like. =20 >Now you mention it, >that example code is somewhat missleading! The issue with >this ring buffer implementation is the handling of a true=20 >blocking read is complex >as at any given time you aren't guaranteed to get what you=20 >asked for even if it was >there when you started the read. It should be possible to work=20 >around that though. > >It's possible this functionality might be better added to an=20 >alternative ring buffer >implementation. Be vary wary of that ring implementation in=20 >general! I am and I wrote it. Then I will not begin to add any new feature in current ring buffer.=20 >> If you agree with that, I can begin to add these and send=20 >you a patch. >> And a problem I don't know is what you and other people have=20 >changed to >> Greg's staging tree, and I am not sure what tree the patch should be >> againest.=20 >Nothing has changed in this region of the code. In fact I=20 >think all that >has gone into Greg's tree is a clean up patch form Mark Brown=20 >making a few >functions static. Right now I'm still getting the max1363 driver into >a state where it will be possible to do the ABI changes. >>=20 >> For long term plan, is it possible for ring common level to=20 >handle more >> common work to avoid code repeating in different drivers? >I'm certainly happy for that to be the case if it becomes=20 >apparent which functionality >is shared. I haven't seen any substantial cases as yet, but=20 >then I may well be missing >things so feel free to submit suggestions (or as ever the=20 >better option of patches). If possibe, the SW ring buffer can hide more details. Users only need to do two things in drivers: 1. register device with ring support. 2. push data to ring in the interrupt bottom half. And even though some devices have HW ring, it is maybe not needed to export any detail to users at all.=20 It only means the driver developpers use a different way to read data from HW and push data to SW ring. To users, all can be SW rings. I am not sure whether it will be better for an architecture. > >Thanks, > >Jonathan > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-02-23 4:11 ` Song, Barry @ 2010-02-23 11:44 ` Jonathan Cameron 2010-02-24 6:42 ` Song, Barry 0 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-02-23 11:44 UTC (permalink / raw) To: Song, Barry; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio Hi Barry, >> >> Just for reference as I'll be doing a proper announcement later. >> We now have linux-iio@vger.kernel.org as a mailing list for >> the project. > > That's great. Lucky to become the 2nd member. Welcome :) > >> Unless others have tracked it down it currently only has me as a member >> though and I'm waiting for confirmation from marc.info of an archive. >> >>> Hi Jonathan, >>> Now users depend on iio ring >> events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>> to read data: >>> read_size = fread(&dat, 1, sizeof(struct >>> iio_event_data), >>> fp_ev); >>> switch (dat.id) { >>> case IIO_EVENT_CODE_RING_100_FULL: >>> toread = RingLength; >>> break; >>> case IIO_EVENT_CODE_RING_75_FULL: >>> toread = RingLength*3/4; >>> break; >>> case IIO_EVENT_CODE_RING_50_FULL: >>> toread = RingLength/2; >>> break; >>> default: >>> printf("Unexpecteded event code\n"); >>> continue; >>> } >>> read_size = read(fp, >>> data, >>> toread*size_from_scanmode(NumVals, >>> scan_ts)); >>> if (read_size == -EAGAIN) { >>> printf("nothing available \n"); >>> continue; >>> } >>> And iio ring access node doesn't support blocking io too. >> It seems we >>> lost to let users read data once ring is not empty. And some >> users maybe >>> not care about iio ring events at all, but just want to read >> data like a >>> input or audio driver. So how about adding the following >> support in iio >>> ring: >>> 1. add NOT EMPTY event in IIO event nodes >> Not keen. It might lead to a storm of events (at least it might in a >> cleverer ring buffer implementation or during a blocking >> read). Actually >> in this particular case it probably wouldn't do any harm. >>> 2. add blocking io support in read function of IIO access nodes >> That I agree would be a good idea. If we support poll/select >> on the buffer access >> chrdev then we will get the same effect per having a not empty >> event and cleaner >> semantics for anyone not interested in the other events. Not >> to mention I expect >> we will soon have alternative ring buffer implementations that >> don't supply any >> events at all and hence don't event have the relevant chrdev. > > That means 50%, 75%, 100% event will disappear and the ring event node > will disappear too? > In fact, I doesn't understand the original purpose for those events. To > support HW ring buffer > notification to users? Partly for hardware events and partly because the 50% full type events are what I needed. If we were to use a chrdev on which we could select then where would you set that boundary? The only place it makes sense to set it is the 'is there anything in the buffer point'. In a block based type algorithm running on the data on top (or for that matter writing to external flash etc) we really don't care if there is one set of readings in there. We are only interested once there are a lot more and would like to be doing other things in the meantime. Thus no they don't go away unless we can find better semantics for everything they tell us (and I'm open to suggestions). Note that it may be very hard / impossible for userspace to 'know' what is a sensible interval to wait for a decent amount of data to be in the ring buffer and for it hence to be sensible to do a read as the trigger events may vary enormously. >> >> As things are, you can quite happily read whenever you like. >> Now you mention it, >> that example code is somewhat missleading! The issue with >> this ring buffer implementation is the handling of a true >> blocking read is complex >> as at any given time you aren't guaranteed to get what you >> asked for even if it was >> there when you started the read. It should be possible to work >> around that though. >> >> It's possible this functionality might be better added to an >> alternative ring buffer >> implementation. Be vary wary of that ring implementation in >> general! I am and I wrote it. > > Then I will not begin to add any new feature in current ring buffer. Cool, though beware it may be some time until a better option is in place and all the 'kinks' have been ironed out. This area is definitely the biggest target left in the todo list! If nothing else I want to experiment with buffers based on kfifo and the lockless buffer that came out of tracing. In their raw form neither of these provides us with these sort of events anyway and as such won't have event chrdevs. > >>> If you agree with that, I can begin to add these and send >> you a patch. >>> And a problem I don't know is what you and other people have >> changed to >>> Greg's staging tree, and I am not sure what tree the patch should be >>> againest. >> Nothing has changed in this region of the code. In fact I >> think all that >> has gone into Greg's tree is a clean up patch form Mark Brown >> making a few >> functions static. Right now I'm still getting the max1363 driver into >> a state where it will be possible to do the ABI changes. >>> >>> For long term plan, is it possible for ring common level to >> handle more >>> common work to avoid code repeating in different drivers? >> I'm certainly happy for that to be the case if it becomes >> apparent which functionality >> is shared. I haven't seen any substantial cases as yet, but >> then I may well be missing >> things so feel free to submit suggestions (or as ever the >> better option of patches). > > If possibe, the SW ring buffer can hide more details. Users only need to > do two things in drivers: > 1. register device with ring support. > 2. push data to ring in the interrupt bottom half. > And even though some devices have HW ring, it is maybe not needed to > export any detail to users at all. > It only means the driver developpers use a different way to read data > from HW and push data to SW ring. > To users, all can be SW rings. I am not sure whether it will be better > for an architecture. The only other interactions in there at the moment are: 1. The ability to grab data from the ring when a direct channel read is made from the sysfs interface. This is optional and device specific anyway. 2. The ability to control which elements are being buffered. Again this is optional. Here the only interaction is making appropriate changes to the ring buffer allocation. This is really there for reasons of semantics. To a user it makes more sense to request a buffer to take say 1000 'scans' of channels 1,3 and 5 than to directly control the ring buffer size. This could probably move into the userspace library once the new ABI is in place though I haven't thought that option through completely yet. 3. All the preenable, post enable etc. Yes, in some cases these could move into the core, but I've run into enough device specific quirks that we will probably need these hooks to be available, even if one normally just leaves them undefined and hence gets the default. I think for these we leave it in the driver for a now and do the change as a refactoring once we have enough drivers with the same code to justify what goes in the default. So as far as I can see only point 3 could sensibly be merged with the core and that not yet. The first two are handy features that require more 'hooks' but they certainly aren't obligatory. As for the all rings are software approach, this may make sense, but I'm not inclined to move that way until we have a decent range of software rings in place. Right now for the sca3000 driver, the ring buffer is substantial, reliable and if we don't want all the data, leaving it on chip will minimize the bus traffic. (given how slow the i2c bus for that chip is, this can be important!) Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: IIO ring buffer 2010-02-23 11:44 ` Jonathan Cameron @ 2010-02-24 6:42 ` Song, Barry 2010-02-24 6:48 ` [Uclinux-dist-devel] " Song, Barry 2010-02-24 14:10 ` Jonathan Cameron 0 siblings, 2 replies; 31+ messages in thread From: Song, Barry @ 2010-02-24 6:42 UTC (permalink / raw) To: Jonathan Cameron; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio =20 >-----Original Message----- >From: Jonathan Cameron [mailto:jic23@cam.ac.uk]=20 >Sent: Tuesday, February 23, 2010 7:45 PM >To: Song, Barry >Cc: jic23@hermes.cam.ac.uk; manuel.stahl@iis.fraunhofer.de;=20 >uclinux-dist-devel@blackfin.uclinux.org; linux-iio@vger.kernel.org >Subject: Re: IIO ring buffer > >Hi Barry, >>> >>> Just for reference as I'll be doing a proper announcement later. >>> We now have linux-iio@vger.kernel.org as a mailing list for=20 >>> the project. >>=20 >> That's great. Lucky to become the 2nd member. >Welcome :) >>=20 >>> Unless others have tracked it down it currently only has me=20 >as a member >>> though and I'm waiting for confirmation from marc.info of=20 >an archive. >>> >>>> Hi Jonathan, >>>> Now users depend on iio ring=20 >>> events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>>> to read data: >>>> read_size =3D fread(&dat, 1, sizeof(struct >>>> iio_event_data), >>>> fp_ev); >>>> switch (dat.id) { >>>> case IIO_EVENT_CODE_RING_100_FULL: >>>> toread =3D RingLength; >>>> break; >>>> case IIO_EVENT_CODE_RING_75_FULL: >>>> toread =3D RingLength*3/4; >>>> break; >>>> case IIO_EVENT_CODE_RING_50_FULL: >>>> toread =3D RingLength/2; >>>> break; >>>> default: >>>> printf("Unexpecteded event code\n"); >>>> continue; >>>> } =20 >>>> read_size =3D read(fp, >>>> data, >>>> toread*size_from_scanmode(NumVals, >>>> scan_ts)); >>>> if (read_size =3D=3D -EAGAIN) { >>>> printf("nothing available \n"); >>>> continue; >>>> } =20 >>>> And iio ring access node doesn't support blocking io too. =20 >>> It seems we >>>> lost to let users read data once ring is not empty. And some=20 >>> users maybe >>>> not care about iio ring events at all, but just want to read=20 >>> data like a >>>> input or audio driver. So how about adding the following=20 >>> support in iio >>>> ring: >>>> 1. add NOT EMPTY event in IIO event nodes >>> Not keen. It might lead to a storm of events (at least it=20 >might in a=20 >>> cleverer ring buffer implementation or during a blocking=20 >>> read). Actually >>> in this particular case it probably wouldn't do any harm. >>>> 2. add blocking io support in read function of IIO access nodes >>> That I agree would be a good idea. If we support poll/select=20 >>> on the buffer access >>> chrdev then we will get the same effect per having a not empty=20 >>> event and cleaner >>> semantics for anyone not interested in the other events. Not=20 >>> to mention I expect >>> we will soon have alternative ring buffer implementations that=20 >>> don't supply any >>> events at all and hence don't event have the relevant chrdev. >>=20 >> That means 50%, 75%, 100% event will disappear and the ring=20 >event node >> will disappear too? =20 >> In fact, I doesn't understand the original purpose for those=20 >events. To >> support HW ring buffer >> notification to users? >Partly for hardware events and partly because the 50% full type events >are what I needed. If we were to use a chrdev on which we could select >then where would you set that boundary? The only place it makes sense >to set it is the 'is there anything in the buffer point'. In a block >based type algorithm running on the data on top (or for that matter >writing to external flash etc) we really don't care if there is one >set of readings in there. We are only interested once there are a lot >more and would like to be doing other things in the meantime.=20 >Thus no they don't go away unless we can find better semantics for >everything they tell us (and I'm open to suggestions). Note that it >may be very hard / impossible for userspace to 'know' what is=20 >a sensible >interval to wait for a decent amount of data to be in the ring=20 >buffer and >for it hence to be sensible to do a read as the trigger events may >vary enormously.=20 >>> >>> As things are, you can quite happily read whenever you like. =20 >>> Now you mention it, >>> that example code is somewhat missleading! The issue with >>> this ring buffer implementation is the handling of a true=20 >>> blocking read is complex >>> as at any given time you aren't guaranteed to get what you=20 >>> asked for even if it was >>> there when you started the read. It should be possible to work=20 >>> around that though. >>> >>> It's possible this functionality might be better added to an=20 >>> alternative ring buffer >>> implementation. Be vary wary of that ring implementation in=20 >>> general! I am and I wrote it. >>=20 >> Then I will not begin to add any new feature in current ring buffer. >Cool, though beware it may be some time until a better option is in >place and all the 'kinks' have been ironed out. This area is definitely >the biggest target left in the todo list! If nothing else I want to >experiment with buffers based on kfifo and the lockless buffer=20 >that came >out of tracing. In their raw form neither of these provides us with >these sort of events anyway and as such won't have event chrdevs. >>=20 >>>> If you agree with that, I can begin to add these and send=20 >>> you a patch. >>>> And a problem I don't know is what you and other people have=20 >>> changed to >>>> Greg's staging tree, and I am not sure what tree the patch=20 >should be >>>> againest.=20 >>> Nothing has changed in this region of the code. In fact I=20 >>> think all that >>> has gone into Greg's tree is a clean up patch form Mark Brown=20 >>> making a few >>> functions static. Right now I'm still getting the max1363=20 >driver into >>> a state where it will be possible to do the ABI changes. >>>> >>>> For long term plan, is it possible for ring common level to=20 >>> handle more >>>> common work to avoid code repeating in different drivers? >>> I'm certainly happy for that to be the case if it becomes=20 >>> apparent which functionality >>> is shared. I haven't seen any substantial cases as yet, but=20 >>> then I may well be missing >>> things so feel free to submit suggestions (or as ever the=20 >>> better option of patches). >>=20 >> If possibe, the SW ring buffer can hide more details. Users=20 >only need to >> do two things in drivers: >> 1. register device with ring support. >> 2. push data to ring in the interrupt bottom half. >> And even though some devices have HW ring, it is maybe not needed to >> export any detail to users at all.=20 >> It only means the driver developpers use a different way to read data >> from HW and push data to SW ring. >> To users, all can be SW rings. I am not sure whether it will=20 >be better >> for an architecture. >The only other interactions in there at the moment are: >1. The ability to grab data from the ring when a direct=20 >channel read is made > from the sysfs interface. This is optional and device=20 >specific anyway. >2. The ability to control which elements are being buffered. =20 >Again this is > optional. Here the only interaction is making appropriate=20 >changes to the > ring buffer allocation. This is really there for reasons of=20 >semantics. > To a user it makes more sense to request a buffer to take=20 >say 1000 'scans' > of channels 1,3 and 5 than to directly control the ring buffer size. > This could probably move into the userspace library once=20 >the new ABI is in > place though I haven't thought that option through completely yet. >3. All the preenable, post enable etc. Yes, in some cases=20 >these could move into > the core, but I've run into enough device specific quirks=20 >that we will probably > need these hooks to be available, even if one normally just=20 >leaves them undefined > and hence gets the default. I think for these we leave it=20 >in the driver for a now and > do the change as a refactoring once we have enough drivers=20 >with the same code > to justify what goes in the default. > >So as far as I can see only point 3 could sensibly be merged=20 >with the core and that >not yet. The first two are handy features that require more=20 >'hooks' but they certainly >aren't obligatory. > >As for the all rings are software approach, this may make=20 >sense, but I'm not inclined >to move that way until we have a decent range of software=20 >rings in place. Right now >for the sca3000 driver, the ring buffer is substantial,=20 >reliable and if we don't want >all the data, leaving it on chip will minimize the bus=20 >traffic. (given how slow the i2c >bus for that chip is, this can be important!) Another possible problem is the current scan mask is maybe not too common. Some devices can't support n functions to work at the same time, but can only support 1 from n or m from n. So sometimes mask setting can be illegal to real hardware. For example, the ADE7753, sampling data can be only one of Channel 1, Channel 2, or the active power signal. For this kind of cases, IIO will let userspace to manage the mask? I mean if users want to use channel2, users must disable channel 1 and "active power signal", then enable channel 2? IIO core will not do any check about users' mask setting? > >Jonathan > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [Uclinux-dist-devel] IIO ring buffer 2010-02-24 6:42 ` Song, Barry @ 2010-02-24 6:48 ` Song, Barry 2010-02-24 14:10 ` Jonathan Cameron 1 sibling, 0 replies; 31+ messages in thread From: Song, Barry @ 2010-02-24 6:48 UTC (permalink / raw) To: Song, Barry, Jonathan Cameron Cc: linux-iio, uclinux-dist-devel, manuel.stahl, jic23 =20 >-----Original Message----- >From: uclinux-dist-devel-bounces@blackfin.uclinux.org=20 >[mailto:uclinux-dist-devel-bounces@blackfin.uclinux.org] On=20 >Behalf Of Song, Barry >Sent: Wednesday, February 24, 2010 2:43 PM >To: Jonathan Cameron >Cc: linux-iio@vger.kernel.org;=20 >uclinux-dist-devel@blackfin.uclinux.org;=20 >manuel.stahl@iis.fraunhofer.de; jic23@hermes.cam.ac.uk >Subject: Re: [Uclinux-dist-devel] IIO ring buffer > > >=20 > >>-----Original Message----- >>From: Jonathan Cameron [mailto:jic23@cam.ac.uk]=20 >>Sent: Tuesday, February 23, 2010 7:45 PM >>To: Song, Barry >>Cc: jic23@hermes.cam.ac.uk; manuel.stahl@iis.fraunhofer.de;=20 >>uclinux-dist-devel@blackfin.uclinux.org; linux-iio@vger.kernel.org >>Subject: Re: IIO ring buffer >> >>Hi Barry, >>>> >>>> Just for reference as I'll be doing a proper announcement later. >>>> We now have linux-iio@vger.kernel.org as a mailing list for=20 >>>> the project. >>>=20 >>> That's great. Lucky to become the 2nd member. >>Welcome :) >>>=20 >>>> Unless others have tracked it down it currently only has me=20 >>as a member >>>> though and I'm waiting for confirmation from marc.info of=20 >>an archive. >>>> >>>>> Hi Jonathan, >>>>> Now users depend on iio ring=20 >>>> events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>>>> to read data: >>>>> read_size =3D fread(&dat, 1, sizeof(struct >>>>> iio_event_data), >>>>> fp_ev); >>>>> switch (dat.id) { >>>>> case IIO_EVENT_CODE_RING_100_FULL: >>>>> toread =3D RingLength; >>>>> break; >>>>> case IIO_EVENT_CODE_RING_75_FULL: >>>>> toread =3D RingLength*3/4; >>>>> break; >>>>> case IIO_EVENT_CODE_RING_50_FULL: >>>>> toread =3D RingLength/2; >>>>> break; >>>>> default: >>>>> printf("Unexpecteded event code\n"); >>>>> continue; >>>>> } =20 >>>>> read_size =3D read(fp, >>>>> data, >>>>> =20 >toread*size_from_scanmode(NumVals, >>>>> scan_ts)); >>>>> if (read_size =3D=3D -EAGAIN) { >>>>> printf("nothing available \n"); >>>>> continue; >>>>> } =20 >>>>> And iio ring access node doesn't support blocking io too. =20 >>>> It seems we >>>>> lost to let users read data once ring is not empty. And some=20 >>>> users maybe >>>>> not care about iio ring events at all, but just want to read=20 >>>> data like a >>>>> input or audio driver. So how about adding the following=20 >>>> support in iio >>>>> ring: >>>>> 1. add NOT EMPTY event in IIO event nodes >>>> Not keen. It might lead to a storm of events (at least it=20 >>might in a=20 >>>> cleverer ring buffer implementation or during a blocking=20 >>>> read). Actually >>>> in this particular case it probably wouldn't do any harm. >>>>> 2. add blocking io support in read function of IIO access nodes >>>> That I agree would be a good idea. If we support poll/select=20 >>>> on the buffer access >>>> chrdev then we will get the same effect per having a not empty=20 >>>> event and cleaner >>>> semantics for anyone not interested in the other events. Not=20 >>>> to mention I expect >>>> we will soon have alternative ring buffer implementations that=20 >>>> don't supply any >>>> events at all and hence don't event have the relevant chrdev. >>>=20 >>> That means 50%, 75%, 100% event will disappear and the ring=20 >>event node >>> will disappear too? =20 >>> In fact, I doesn't understand the original purpose for those=20 >>events. To >>> support HW ring buffer >>> notification to users? >>Partly for hardware events and partly because the 50% full type events >>are what I needed. If we were to use a chrdev on which we could select >>then where would you set that boundary? The only place it makes sense >>to set it is the 'is there anything in the buffer point'. In a block >>based type algorithm running on the data on top (or for that matter >>writing to external flash etc) we really don't care if there is one >>set of readings in there. We are only interested once there are a lot >>more and would like to be doing other things in the meantime.=20 >>Thus no they don't go away unless we can find better semantics for >>everything they tell us (and I'm open to suggestions). Note that it >>may be very hard / impossible for userspace to 'know' what is=20 >>a sensible >>interval to wait for a decent amount of data to be in the ring=20 >>buffer and >>for it hence to be sensible to do a read as the trigger events may >>vary enormously.=20 >>>> >>>> As things are, you can quite happily read whenever you like. =20 >>>> Now you mention it, >>>> that example code is somewhat missleading! The issue with >>>> this ring buffer implementation is the handling of a true=20 >>>> blocking read is complex >>>> as at any given time you aren't guaranteed to get what you=20 >>>> asked for even if it was >>>> there when you started the read. It should be possible to work=20 >>>> around that though. >>>> >>>> It's possible this functionality might be better added to an=20 >>>> alternative ring buffer >>>> implementation. Be vary wary of that ring implementation in=20 >>>> general! I am and I wrote it. >>>=20 >>> Then I will not begin to add any new feature in current ring buffer. >>Cool, though beware it may be some time until a better option is in >>place and all the 'kinks' have been ironed out. This area is=20 >definitely >>the biggest target left in the todo list! If nothing else I want to >>experiment with buffers based on kfifo and the lockless buffer=20 >>that came >>out of tracing. In their raw form neither of these provides us with >>these sort of events anyway and as such won't have event chrdevs. >>>=20 >>>>> If you agree with that, I can begin to add these and send=20 >>>> you a patch. >>>>> And a problem I don't know is what you and other people have=20 >>>> changed to >>>>> Greg's staging tree, and I am not sure what tree the patch=20 >>should be >>>>> againest.=20 >>>> Nothing has changed in this region of the code. In fact I=20 >>>> think all that >>>> has gone into Greg's tree is a clean up patch form Mark Brown=20 >>>> making a few >>>> functions static. Right now I'm still getting the max1363=20 >>driver into >>>> a state where it will be possible to do the ABI changes. >>>>> >>>>> For long term plan, is it possible for ring common level to=20 >>>> handle more >>>>> common work to avoid code repeating in different drivers? >>>> I'm certainly happy for that to be the case if it becomes=20 >>>> apparent which functionality >>>> is shared. I haven't seen any substantial cases as yet, but=20 >>>> then I may well be missing >>>> things so feel free to submit suggestions (or as ever the=20 >>>> better option of patches). >>>=20 >>> If possibe, the SW ring buffer can hide more details. Users=20 >>only need to >>> do two things in drivers: >>> 1. register device with ring support. >>> 2. push data to ring in the interrupt bottom half. >>> And even though some devices have HW ring, it is maybe not needed to >>> export any detail to users at all.=20 >>> It only means the driver developpers use a different way to=20 >read data >>> from HW and push data to SW ring. >>> To users, all can be SW rings. I am not sure whether it will=20 >>be better >>> for an architecture. >>The only other interactions in there at the moment are: >>1. The ability to grab data from the ring when a direct=20 >>channel read is made >> from the sysfs interface. This is optional and device=20 >>specific anyway. >>2. The ability to control which elements are being buffered. =20 >>Again this is >> optional. Here the only interaction is making appropriate=20 >>changes to the >> ring buffer allocation. This is really there for reasons of=20 >>semantics. >> To a user it makes more sense to request a buffer to take=20 >>say 1000 'scans' >> of channels 1,3 and 5 than to directly control the ring=20 >buffer size. >> This could probably move into the userspace library once=20 >>the new ABI is in >> place though I haven't thought that option through completely yet. >>3. All the preenable, post enable etc. Yes, in some cases=20 >>these could move into >> the core, but I've run into enough device specific quirks=20 >>that we will probably >> need these hooks to be available, even if one normally just=20 >>leaves them undefined >> and hence gets the default. I think for these we leave it=20 >>in the driver for a now and >> do the change as a refactoring once we have enough drivers=20 >>with the same code >> to justify what goes in the default. >> >>So as far as I can see only point 3 could sensibly be merged=20 >>with the core and that >>not yet. The first two are handy features that require more=20 >>'hooks' but they certainly >>aren't obligatory. >> >>As for the all rings are software approach, this may make=20 >>sense, but I'm not inclined >>to move that way until we have a decent range of software=20 >>rings in place. Right now >>for the sca3000 driver, the ring buffer is substantial,=20 >>reliable and if we don't want >>all the data, leaving it on chip will minimize the bus=20 >>traffic. (given how slow the i2c >>bus for that chip is, this can be important!) >Another possible problem is the current scan mask is maybe not too >common. Some devices can't support n functions to work at the=20 >same time, >but can only support 1 from n or m from n. So sometimes mask=20 >setting can >be illegal to real hardware. >For example, the ADE7753, sampling data can be only one of Channel 1, >Channel 2, or the active power signal. For this kind of cases, IIO will >let userspace to manage the mask? I mean if users want to use channel2, >users must disable channel 1 and "active power signal", then enable >channel 2? IIO core will not do any check about users' mask setting? If possible, could we add a callback in: static inline int iio_scan_mask_set(struct iio_dev *dev_info, int bit) { if (bit > IIO_MAX_SCAN_LENGTH) return -EINVAL; dev_info->scan_mask |=3D (1 << bit); dev_info->scan_count++; return 0; }; Like this: static inline int iio_scan_mask_set(struct iio_dev *dev_info, int bit) { if (bit > IIO_MAX_SCAN_LENGTH) return -EINVAL; + if (dev_info->ops->scan_mask_set) + dev_info->ops->scan_mask_set(struct iio_dev *dev_info, int bit); + else { dev_info->scan_mask |=3D (1 << bit); dev_info->scan_count++; + } return 0; }; Or other way? > >> >>Jonathan >> >> >_______________________________________________ >Uclinux-dist-devel mailing list >Uclinux-dist-devel@blackfin.uclinux.org >https://blackfin.uclinux.org/mailman/listinfo/uclinux-dist-devel > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-02-24 6:42 ` Song, Barry 2010-02-24 6:48 ` [Uclinux-dist-devel] " Song, Barry @ 2010-02-24 14:10 ` Jonathan Cameron 2010-03-02 9:57 ` Barry Song 1 sibling, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-02-24 14:10 UTC (permalink / raw) To: Song, Barry; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio On 02/24/10 06:42, Song, Barry wrote: > > >> -----Original Message----- >> From: Jonathan Cameron [mailto:jic23@cam.ac.uk] >> Sent: Tuesday, February 23, 2010 7:45 PM >> To: Song, Barry >> Cc: jic23@hermes.cam.ac.uk; manuel.stahl@iis.fraunhofer.de; >> uclinux-dist-devel@blackfin.uclinux.org; linux-iio@vger.kernel.org >> Subject: Re: IIO ring buffer >> >> Hi Barry, >>>> >>>> Just for reference as I'll be doing a proper announcement later. >>>> We now have linux-iio@vger.kernel.org as a mailing list for >>>> the project. >>> >>> That's great. Lucky to become the 2nd member. >> Welcome :) >>> >>>> Unless others have tracked it down it currently only has me >> as a member >>>> though and I'm waiting for confirmation from marc.info of >> an archive. >>>> >>>>> Hi Jonathan, >>>>> Now users depend on iio ring >>>> events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>>>> to read data: >>>>> read_size = fread(&dat, 1, sizeof(struct >>>>> iio_event_data), >>>>> fp_ev); >>>>> switch (dat.id) { >>>>> case IIO_EVENT_CODE_RING_100_FULL: >>>>> toread = RingLength; >>>>> break; >>>>> case IIO_EVENT_CODE_RING_75_FULL: >>>>> toread = RingLength*3/4; >>>>> break; >>>>> case IIO_EVENT_CODE_RING_50_FULL: >>>>> toread = RingLength/2; >>>>> break; >>>>> default: >>>>> printf("Unexpecteded event code\n"); >>>>> continue; >>>>> } >>>>> read_size = read(fp, >>>>> data, >>>>> toread*size_from_scanmode(NumVals, >>>>> scan_ts)); >>>>> if (read_size == -EAGAIN) { >>>>> printf("nothing available \n"); >>>>> continue; >>>>> } >>>>> And iio ring access node doesn't support blocking io too. >>>> It seems we >>>>> lost to let users read data once ring is not empty. And some >>>> users maybe >>>>> not care about iio ring events at all, but just want to read >>>> data like a >>>>> input or audio driver. So how about adding the following >>>> support in iio >>>>> ring: >>>>> 1. add NOT EMPTY event in IIO event nodes >>>> Not keen. It might lead to a storm of events (at least it >> might in a >>>> cleverer ring buffer implementation or during a blocking >>>> read). Actually >>>> in this particular case it probably wouldn't do any harm. >>>>> 2. add blocking io support in read function of IIO access nodes >>>> That I agree would be a good idea. If we support poll/select >>>> on the buffer access >>>> chrdev then we will get the same effect per having a not empty >>>> event and cleaner >>>> semantics for anyone not interested in the other events. Not >>>> to mention I expect >>>> we will soon have alternative ring buffer implementations that >>>> don't supply any >>>> events at all and hence don't event have the relevant chrdev. >>> >>> That means 50%, 75%, 100% event will disappear and the ring >> event node >>> will disappear too? >>> In fact, I doesn't understand the original purpose for those >> events. To >>> support HW ring buffer >>> notification to users? >> Partly for hardware events and partly because the 50% full type events >> are what I needed. If we were to use a chrdev on which we could select >> then where would you set that boundary? The only place it makes sense >> to set it is the 'is there anything in the buffer point'. In a block >> based type algorithm running on the data on top (or for that matter >> writing to external flash etc) we really don't care if there is one >> set of readings in there. We are only interested once there are a lot >> more and would like to be doing other things in the meantime. >> Thus no they don't go away unless we can find better semantics for >> everything they tell us (and I'm open to suggestions). Note that it >> may be very hard / impossible for userspace to 'know' what is >> a sensible >> interval to wait for a decent amount of data to be in the ring >> buffer and >> for it hence to be sensible to do a read as the trigger events may >> vary enormously. >>>> >>>> As things are, you can quite happily read whenever you like. >>>> Now you mention it, >>>> that example code is somewhat missleading! The issue with >>>> this ring buffer implementation is the handling of a true >>>> blocking read is complex >>>> as at any given time you aren't guaranteed to get what you >>>> asked for even if it was >>>> there when you started the read. It should be possible to work >>>> around that though. >>>> >>>> It's possible this functionality might be better added to an >>>> alternative ring buffer >>>> implementation. Be vary wary of that ring implementation in >>>> general! I am and I wrote it. >>> >>> Then I will not begin to add any new feature in current ring buffer. >> Cool, though beware it may be some time until a better option is in >> place and all the 'kinks' have been ironed out. This area is definitely >> the biggest target left in the todo list! If nothing else I want to >> experiment with buffers based on kfifo and the lockless buffer >> that came >> out of tracing. In their raw form neither of these provides us with >> these sort of events anyway and as such won't have event chrdevs. >>> >>>>> If you agree with that, I can begin to add these and send >>>> you a patch. >>>>> And a problem I don't know is what you and other people have >>>> changed to >>>>> Greg's staging tree, and I am not sure what tree the patch >> should be >>>>> againest. >>>> Nothing has changed in this region of the code. In fact I >>>> think all that >>>> has gone into Greg's tree is a clean up patch form Mark Brown >>>> making a few >>>> functions static. Right now I'm still getting the max1363 >> driver into >>>> a state where it will be possible to do the ABI changes. >>>>> >>>>> For long term plan, is it possible for ring common level to >>>> handle more >>>>> common work to avoid code repeating in different drivers? >>>> I'm certainly happy for that to be the case if it becomes >>>> apparent which functionality >>>> is shared. I haven't seen any substantial cases as yet, but >>>> then I may well be missing >>>> things so feel free to submit suggestions (or as ever the >>>> better option of patches). >>> >>> If possibe, the SW ring buffer can hide more details. Users >> only need to >>> do two things in drivers: >>> 1. register device with ring support. >>> 2. push data to ring in the interrupt bottom half. >>> And even though some devices have HW ring, it is maybe not needed to >>> export any detail to users at all. >>> It only means the driver developpers use a different way to read data >>> from HW and push data to SW ring. >>> To users, all can be SW rings. I am not sure whether it will >> be better >>> for an architecture. >> The only other interactions in there at the moment are: >> 1. The ability to grab data from the ring when a direct >> channel read is made >> from the sysfs interface. This is optional and device >> specific anyway. >> 2. The ability to control which elements are being buffered. >> Again this is >> optional. Here the only interaction is making appropriate >> changes to the >> ring buffer allocation. This is really there for reasons of >> semantics. >> To a user it makes more sense to request a buffer to take >> say 1000 'scans' >> of channels 1,3 and 5 than to directly control the ring buffer size. >> This could probably move into the userspace library once >> the new ABI is in >> place though I haven't thought that option through completely yet. >> 3. All the preenable, post enable etc. Yes, in some cases >> these could move into >> the core, but I've run into enough device specific quirks >> that we will probably >> need these hooks to be available, even if one normally just >> leaves them undefined >> and hence gets the default. I think for these we leave it >> in the driver for a now and >> do the change as a refactoring once we have enough drivers >> with the same code >> to justify what goes in the default. >> >> So as far as I can see only point 3 could sensibly be merged >> with the core and that >> not yet. The first two are handy features that require more >> 'hooks' but they certainly >> aren't obligatory. >> >> As for the all rings are software approach, this may make >> sense, but I'm not inclined >> to move that way until we have a decent range of software >> rings in place. Right now >> for the sca3000 driver, the ring buffer is substantial, >> reliable and if we don't want >> all the data, leaving it on chip will minimize the bus >> traffic. (given how slow the i2c >> bus for that chip is, this can be important!) > Another possible problem is the current scan mask is maybe not too > common. Some devices can't support n functions to work at the same time, > but can only support 1 from n or m from n. So sometimes mask setting can > be illegal to real hardware. > For example, the ADE7753, sampling data can be only one of Channel 1, > Channel 2, or the active power signal. For this kind of cases, IIO will > let userspace to manage the mask? I mean if users want to use channel2, > users must disable channel 1 and "active power signal", then enable > channel 2? IIO core will not do any check about users' mask setting? This exact issue is why the rewrite of the max1363 driver set is taking me so long. The intention is the following... (this got discussed a few weeks back, though it was pre mailing list so I'll cover where we ended up in some depth. For reference it was quite a way down in the thread entitled simply IIO that Michael Hennerich started, it's there in an email from the 2/2/2010). You have identified once of the main problems we ran into when trying to work out a consistent API for dealing with what I will call 'Scan mode configuration' Some devices either provide complete control, or don't have a concept of a scan at all (in which case we just query the registers corresponding to the readings we want, or as in many adc's write the required channel in parallel with 1 or 2 reads before it actually occurs, e.g. ad7949 which I'm currently using in a baremetal design and hence am far too familiar with :). Some devices only allow 'scans' consisting of certain combinations of channels. The interface that currently exists for the max1363 in mainline is an example of how this can be controlled via a rather complex set of sysfs files. As IIO in mainline currently stands there are thus 2 approaches for controlling the 'Scan mode' of devices, that of the max1363 where we use asci strings and that of everything else where the channels have independent 'enable' sysfs controls. The 'cunning' plan was to try and unify these before we do the ABI changes to meet the specification sent out recently. The most adaptable and predictable of the two approaches is the one where every channel is apparently independently controlled (i.e. not the max1363 one!) So as to how this will work, Userspace sees exactly the same as if all channels were independent from the point of view of what files exist. Then the user attempts to set the mask they want, which is matched against an internal set of masks (or a function if you have nice clean cases like above). (This requires keeping track of what has been requested). As each channel is requested we work out which scan mode includes everything desired and as few as possible other channels. The userspace library rereads all the scan enable files to find out what it actually got, prior to starting the ring up. Thus say you request channels, 0, 1, 3. The driver (or core in future) knows that this is 'best' served by a scan consisting of 0,1,2,3. Rereading the individual enable sysfs elements, tells userspace this is what it is actually getting and leaves mangling the results to give the desired channels to userspace. It may make sense in some cases to emulate full hardware mask control (typically 'slow' devices) by munging the data going into the buffer, however this may be costly in time (particularly when we have a device using direct dma into the buffer which is hopefully going to occur shortly. More to follow on that). This was the only approach we could come up with in a previous discussion that was remotely general from the point of view of a userspace interface. It is a bit fiddly, but it covers every possible case. The intent was to implement it in the max1363 driver first to get more general opinions based on actual code rather than a description like this one. At that point I'll probably add a couple more of the drivers for devices that require this functionality (several on the desk in front of me) and then do a nice clean refactor to move shared functionality into the core. As a general rule, this implement in drivers then move into core as appropriate gives a nice clean development model. Thanks, Jonathan p.s. Fingers crossed I'll get the bare metal code that has been eating my time out of the way shortly and get back to actually testing / finishing implementing the max1363 and the follow up api changes! ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-02-24 14:10 ` Jonathan Cameron @ 2010-03-02 9:57 ` Barry Song 2010-03-02 10:45 ` J.I. Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-03-02 9:57 UTC (permalink / raw) To: Jonathan Cameron; +Cc: jic23, manuel.stahl, uclinux-dist-devel, linux-iio Jonathan, I know you are changing iio ring buffer. Here a problem to discuss with you, there are maybe this kind of use cases: the DACs have no internal clock and buffer, so we need an external bus with continuous DMA to "play" data flow with constant speed. It is very similar with alsa driver to play audio by I2S or AC97. ALSA framework is easy to implement this kind of drivers. But our DACs are not audio cards. Then in the iio ring buffer core, it seems we also need APIs like trigger(), pointer(), snd_pcm_period_elapsed()... to get a common framework. Of course, we can let users to handle blocking in write() callback like OSS, but alsa-like APIs should be better. So what's your opinion for that? If I begin to work on this, I am not sure how much is needed to do to merge into your new iio ring buffer codes. So if you have some new codes for reference, it should be better. Thanks Barry On Wed, Feb 24, 2010 at 10:10 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 02/24/10 06:42, Song, Barry wrote: >> >> >>> -----Original Message----- >>> From: Jonathan Cameron [mailto:jic23@cam.ac.uk] >>> Sent: Tuesday, February 23, 2010 7:45 PM >>> To: Song, Barry >>> Cc: jic23@hermes.cam.ac.uk; manuel.stahl@iis.fraunhofer.de; >>> uclinux-dist-devel@blackfin.uclinux.org; linux-iio@vger.kernel.org >>> Subject: Re: IIO ring buffer >>> >>> Hi Barry, >>>>> >>>>> Just for reference as I'll be doing a proper announcement later. >>>>> We now have linux-iio@vger.kernel.org as a mailing list for >>>>> the project. >>>> >>>> That's great. Lucky to become the 2nd member. >>> Welcome :) >>>> >>>>> Unless others have tracked it down it currently only has me >>> as a member >>>>> though and I'm waiting for confirmation from marc.info of >>> an archive. >>>>> >>>>>> Hi Jonathan, >>>>>> Now users depend on iio ring >>>>> events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>>>>> to read data: >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size = =3D fread(&dat, 1, sizeof(struct >>>>>> iio_event_data), >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fp_ev); >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (dat.= id) { >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVE= NT_CODE_RING_100_FULL: >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 toread =3D RingLength; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 break; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVE= NT_CODE_RING_75_FULL: >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 toread =3D RingLength*3/4; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 break; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVE= NT_CODE_RING_50_FULL: >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 toread =3D RingLength/2; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 break; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 default: >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 printf("Unexpecteded event code\n"); >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 continue; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size = =3D read(fp, >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data, >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0toread*size_from_scanmo= de(NumVals, >>>>>> scan_ts)); >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (read_siz= e =3D=3D -EAGAIN) { >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 printf("nothing available \n"); >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 continue; >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>>>> And iio ring access node doesn't support blocking io too. >>>>> It seems we >>>>>> lost to let users read data once ring is not empty. And some >>>>> users maybe >>>>>> not care about iio ring events at all, but just want to read >>>>> data like a >>>>>> input or audio driver. So how about adding the following >>>>> support in iio >>>>>> ring: >>>>>> 1. add NOT EMPTY event in IIO event nodes >>>>> Not keen. =C2=A0It might lead to a storm of events (at least it >>> might in a >>>>> cleverer ring buffer implementation or during a blocking >>>>> read). =C2=A0Actually >>>>> in this particular case it probably wouldn't do any harm. >>>>>> 2. add blocking io support in read function of IIO access nodes >>>>> That I agree would be a good idea. =C2=A0If we support poll/select >>>>> on the buffer access >>>>> chrdev then we will get the same effect per having a not empty >>>>> event and cleaner >>>>> semantics for anyone not interested in the other events. Not >>>>> to mention I expect >>>>> we will soon have alternative ring buffer implementations that >>>>> don't supply any >>>>> events at all and hence don't event have the relevant chrdev. >>>> >>>> That means 50%, 75%, 100% event will disappear and the ring >>> event node >>>> will disappear too? >>>> In fact, I doesn't understand the original purpose for those >>> events. To >>>> support HW ring buffer >>>> notification to users? >>> Partly for hardware events and partly because the 50% full type events >>> are what I needed. If we were to use a chrdev on which we could select >>> then where would you set that boundary? =C2=A0The only place it makes s= ense >>> to set it is the 'is there anything in the buffer point'. =C2=A0 In a b= lock >>> based type algorithm running on the data on top (or for that matter >>> writing to external flash etc) we really don't care if there is one >>> set of readings in there. We are only interested once there are a lot >>> more and would like to be doing other things in the meantime. >>> Thus no they don't go away unless we can find better semantics for >>> everything they tell us (and I'm open to suggestions). =C2=A0Note that = it >>> may be very hard / impossible for userspace to 'know' what is >>> a sensible >>> interval to wait for a decent amount of data to be in the ring >>> buffer and >>> for it hence to be sensible to do a read as the trigger events may >>> vary enormously. >>>>> >>>>> As things are, you can quite happily read whenever you like. >>>>> Now you mention it, >>>>> that example code is somewhat missleading! The issue with >>>>> this ring buffer implementation is the handling of a true >>>>> blocking read is complex >>>>> as at any given time you aren't guaranteed to get what you >>>>> asked for even if it was >>>>> there when you started the read. It should be possible to work >>>>> around that though. >>>>> >>>>> It's possible this functionality might be better added to an >>>>> alternative ring buffer >>>>> implementation. Be vary wary of that ring implementation in >>>>> general! I am and I wrote it. >>>> >>>> Then I will not begin to add any new feature in current ring buffer. >>> Cool, though beware it may be some time until a better option is in >>> place and all the 'kinks' have been ironed out. This area is definitely >>> the biggest target left in the todo list! If nothing else I want to >>> experiment with buffers based on kfifo and the lockless buffer >>> that came >>> out of tracing. =C2=A0In their raw form neither of these provides us wi= th >>> these sort of events anyway and as such won't have event chrdevs. >>>> >>>>>> If you agree with that, I can begin to add these and send >>>>> you a patch. >>>>>> And a problem I don't know is what you and other people have >>>>> changed to >>>>>> Greg's staging tree, and I am not sure what tree the patch >>> should be >>>>>> againest. >>>>> Nothing has changed in this region of the code. =C2=A0In fact I >>>>> think all that >>>>> has gone into Greg's tree is a clean up patch form Mark Brown >>>>> making a few >>>>> functions static. Right now I'm still getting the max1363 >>> driver into >>>>> a state where it will be possible to do the ABI changes. >>>>>> >>>>>> For long term plan, is it possible for ring common level to >>>>> handle more >>>>>> common work to avoid code repeating in different drivers? >>>>> I'm certainly happy for that to be the case if it becomes >>>>> apparent which functionality >>>>> is shared. =C2=A0I haven't seen any substantial cases as yet, but >>>>> then I may well be missing >>>>> things so feel free to submit suggestions (or as ever the >>>>> better option of patches). >>>> >>>> If possibe, the SW ring buffer can hide more details. Users >>> only need to >>>> do two things in drivers: >>>> 1. register device with ring support. >>>> 2. push data to ring in the interrupt bottom half. >>>> And even though some devices have HW ring, it is maybe not needed to >>>> export any detail to users at all. >>>> It only means the driver developpers use a different way to read data >>>> from HW and push data to SW ring. >>>> To users, all can be SW rings. I am not sure whether it will >>> be better >>>> for an architecture. >>> The only other interactions in there at the moment are: >>> 1. The ability to grab data from the ring when a direct >>> channel read is made >>> =C2=A0 from the sysfs interface. =C2=A0This is optional and device >>> specific anyway. >>> 2. The ability to control which elements are being buffered. >>> Again this is >>> =C2=A0 optional. Here the only interaction is making appropriate >>> changes to the >>> =C2=A0 ring buffer allocation. This is really there for reasons of >>> semantics. >>> =C2=A0 To a user it makes more sense to request a buffer to take >>> say 1000 'scans' >>> =C2=A0 of channels 1,3 and 5 than to directly control the ring buffer s= ize. >>> =C2=A0 This could probably move into the userspace library once >>> the new ABI is in >>> =C2=A0 place though I haven't thought that option through completely ye= t. >>> 3. All the preenable, post enable etc. =C2=A0Yes, in some cases >>> these could move into >>> =C2=A0 the core, but I've run into enough device specific quirks >>> that we will probably >>> =C2=A0 need these hooks to be available, even if one normally just >>> leaves them undefined >>> =C2=A0 and hence gets the default. =C2=A0I think for these we leave it >>> in the driver for a now and >>> =C2=A0 do the change as a refactoring once we have enough drivers >>> with the same code >>> =C2=A0 to justify what goes in the default. >>> >>> So as far as I can see only point 3 could sensibly be merged >>> with the core and that >>> not yet. =C2=A0The first two are handy features that require more >>> 'hooks' but they certainly >>> aren't obligatory. >>> >>> As for the all rings are software approach, this may make >>> sense, but I'm not inclined >>> to move that way until we have a decent range of software >>> rings in place. =C2=A0Right now >>> for the sca3000 driver, the ring buffer is substantial, >>> reliable and if we don't want >>> all the data, leaving it on chip will minimize the bus >>> traffic. (given how slow the i2c >>> bus for that chip is, this can be important!) >> Another possible problem is the current scan mask is maybe not too >> common. Some devices can't support n functions to work at the same time, >> but can only support 1 from n or m from n. So sometimes mask setting can >> be illegal to real hardware. >> For example, the ADE7753, sampling data can be only one of Channel 1, >> Channel 2, or the active power signal. For this kind of cases, IIO will >> let userspace to manage the mask? I mean if users want to use channel2, >> users must disable channel 1 and "active power signal", then enable >> channel 2? IIO core will not do any check about users' mask setting? > This exact issue is why the rewrite of the max1363 driver set is taking m= e so > long. > > The intention is the following... (this got discussed a few weeks back, > though it was pre mailing list so I'll cover where we ended up in some de= pth. > For reference it was quite a way down in the thread entitled simply IIO t= hat > Michael Hennerich started, it's there in an email from the 2/2/2010). > > You have identified once of the main problems we ran into when trying to = work > out a consistent API for dealing with what I will call 'Scan mode configu= ration' > Some devices either provide complete control, or don't have a concept of = a scan > at all (in which case we just query the registers corresponding to the re= adings > we want, or as in many adc's write the required channel in parallel with = 1 or > 2 reads before it actually occurs, e.g. ad7949 which I'm currently using = in a > baremetal design and hence am far too familiar with :). Some devices > only allow 'scans' consisting of certain combinations of channels. =C2=A0= The interface > that currently exists for the max1363 in mainline is an example of how th= is > can be controlled via a rather complex set of sysfs files. =C2=A0As IIO i= n mainline > currently stands there are thus 2 approaches for controlling the 'Scan mo= de' > of devices, that of the max1363 where we use asci strings and that of eve= rything > else where the channels have independent 'enable' sysfs controls. > > The 'cunning' plan was to try and unify these before we do the ABI change= s to > meet the specification sent out recently. The most adaptable and predicta= ble > of the two approaches is the one where every channel is apparently indepe= ndently > controlled (i.e. not the max1363 one!) > > So as to how this will work, > > Userspace sees exactly the same as if all channels were independent from = the > point of view of what files exist. > > Then the user attempts to set the mask they want, which is matched agains= t > an internal set of masks (or a function if you have nice clean cases like= above). > (This requires keeping track of what has been requested). > > As each channel is requested we work out which scan mode includes everyth= ing desired > and as few as possible other channels. > > The userspace library rereads all the scan enable files to find out what > it actually got, prior to starting the ring up. > > Thus say you request channels, 0, 1, 3. =C2=A0The driver (or core in futu= re) knows that this > is 'best' served by a scan consisting of 0,1,2,3. =C2=A0Rereading the ind= ividual enable > sysfs elements, tells userspace this is what it is actually getting and l= eaves mangling > the results to give the desired channels to userspace. > > It may make sense in some cases to emulate full hardware mask control (ty= pically > 'slow' devices) by munging the data going into the buffer, however this m= ay be > costly in time (particularly when we have a device using direct dma into = the buffer which > is hopefully going to occur shortly. More to follow on that). > > This was the only approach we could come up with in a previous discussion= that was > remotely general from the point of view of a userspace interface. =C2=A0I= t is a bit > fiddly, but it covers every possible case. > > The intent was to implement it in the max1363 driver first to get more ge= neral > opinions based on actual code rather than a description like this one. > At that point I'll probably add a couple more of the drivers for devices = that require > this functionality (several on the desk in front of me) and then do a nic= e clean > refactor to move shared functionality into the core. =C2=A0As a general r= ule, this > implement in drivers then move into core as appropriate gives a nice clea= n > development model. > > Thanks, > > Jonathan > > p.s. Fingers crossed I'll get the bare metal code that has been eating my= time out of the > way shortly and get back to actually testing / finishing implementing the= max1363 and > the follow up api changes! > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at =C2=A0http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-03-02 9:57 ` Barry Song @ 2010-03-02 10:45 ` J.I. Cameron 2010-03-03 3:26 ` Barry Song 0 siblings, 1 reply; 31+ messages in thread From: J.I. Cameron @ 2010-03-02 10:45 UTC (permalink / raw) To: Barry Song; +Cc: manuel.stahl, uclinux-dist-devel, linux-iio Hi Barry, >I know you are changing iio ring buffer. Here a problem to discuss >with you, there are maybe this kind of use cases: the DACs have no >internal clock and buffer, so we need an external bus with continuous >DMA to "play" data flow with constant speed. It is very similar with >alsa driver to play audio by I2S or AC97. ALSA framework is easy to >implement this kind of drivers. But our DACs are not audio cards. Then >in the iio ring buffer core, it seems we also need APIs like >trigger(), pointer(), snd_pcm_period_elapsed()... to get a common >framework. I have to admit I'm in general a little unclear on how one even goes about getting dma to occur at a constant speed. I'm afraid I haven't had much time to work on improving the ring buffer (though I will try and get a patch out for one particular bug sometime today - if you get issues in the init function with spin locks). Hence, I suggest that you propose any changes you would like to see in the core, if possible with some code along side relevant data sheets so those of us not so familiar with this area can better understand how this would work. My short term plans for the buffering is to allow use of the new implementation of kfifo as it allows dma transfers to occur directly into the buffer. Obviously this will involve adding a few new bits to the api. That internal api is certainly far from locked in stone and as long as we can mend any driver broken by changes, feel free to propose any changes you like! > Of course, we can let users to handle blocking in write() >callback like OSS, but alsa-like APIs should be better. So what's your >opinion for that? >If I begin to work on this, I am not sure how much is needed to do to >merge into your new iio ring buffer codes. So if you have some new >codes for reference, it should be better. Sorry, no new code for now. All changes in my tree are driver based rather than core (and right now to messy to post publicly) Looking forward to seeing what you propose in further detail. Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-03-02 10:45 ` J.I. Cameron @ 2010-03-03 3:26 ` Barry Song 2010-03-03 5:59 ` [Uclinux-dist-devel] " Zhang, Sonic 2010-03-04 12:33 ` Jonathan Cameron 0 siblings, 2 replies; 31+ messages in thread From: Barry Song @ 2010-03-03 3:26 UTC (permalink / raw) To: J.I. Cameron; +Cc: manuel.stahl, uclinux-dist-devel, linux-iio DACs like AD5624R/5644R/5664R(http://www.analog.com/en/digital-to-analog-co= nverters/da-converters/ad5624r/products/product.html) have no clock input and internal buffer. Some users maybe use it to get discrete analog signals, that means once one data is written to AD5624R, one new analog signal is output, then we don't need ring buffer. But some other users maybe want the AD5624R to create continuous signals with a fixed frequency, then we need use ring buffer with linked DMA to input data to AD5624R with a constant rate. This case is same with audio play. To implement that, we need 1. Split ring buffer to some little fragments, one fragment is a DMA block. 2. Ring buffer core layer must handle the play pointer and user writing pointer, stop the DMA automatically when user data under-run flows( valid data is less than one fragment in ring buffer) 3. The DMA interrupt handler in the bottom driver should update the play pointer by a ring buffer core API to notify the play status. 4. The DMA should support linked mode, once one DMA block is finished, another DMA fragment will be enabled by hardware automatically except that it is disabled due to underflow. Thanks Barry On Tue, Mar 2, 2010 at 6:45 PM, J.I. Cameron <jic23@cam.ac.uk> wrote: > Hi Barry, > >> I know you are changing iio ring buffer. Here a problem to discuss >> with you, there are maybe this kind of use cases: the DACs have no >> internal clock and buffer, so we need an external bus with continuous >> DMA to "play" data flow with constant speed. It is very similar with >> alsa driver to play audio by I2S or AC97. ALSA framework is easy to >> implement this kind of drivers. But our DACs are not audio cards. Then >> in the iio ring buffer core, it seems we also need APIs like >> trigger(), pointer(), snd_pcm_period_elapsed()... to get a common >> framework. > > I have to admit I'm in general a little unclear on how one even goes abou= t > getting dma to occur at a constant speed. =C2=A0I'm afraid I haven't had = much > time to work on improving the ring buffer (though I will try and get a pa= tch > out for one particular bug sometime today - if you get issues in the init > function with spin locks). =C2=A0 Hence, I suggest that you propose any c= hanges > you would like to see in the core, if possible with some code along side > relevant data sheets so those of us not so familiar with this area can > better understand how this would work. > > My short term plans for the buffering is to allow use of the new > implementation of kfifo as it allows dma transfers to occur directly into > the buffer. =C2=A0Obviously this will involve adding a few new bits to th= e api. > > That internal api is certainly far from locked in stone and as long as we > can mend any driver broken by changes, feel free to propose any changes y= ou > like! > >> Of course, we can let users to handle blocking in write() >> callback like OSS, but alsa-like APIs should be better. So what's your >> opinion for that? >> If I begin to work on this, I am not sure how much is needed to do to >> merge into your new iio ring buffer codes. So if you have some new >> codes for reference, it should be better. > > Sorry, no new code for now. =C2=A0All changes in my tree are driver based= rather > than core (and right now to messy to post publicly) > > Looking forward to seeing what you propose in further detail. > > Jonathan > ^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [Uclinux-dist-devel] IIO ring buffer 2010-03-03 3:26 ` Barry Song @ 2010-03-03 5:59 ` Zhang, Sonic 2010-03-04 12:33 ` Jonathan Cameron 1 sibling, 0 replies; 31+ messages in thread From: Zhang, Sonic @ 2010-03-03 5:59 UTC (permalink / raw) To: Barry Song, J.I. Cameron; +Cc: linux-iio, uclinux-dist-devel, manuel.stahl I think Barry forgot to mention that this DAC is connect to the CPU via = a 3 PIN serial port with SYNC clock enabled. This serial port controller = has DMA master capability and output data at a given clock. The ring = buffer slots and size is better to be configurable and its API should be = able to trigger output start/stop to IIO driver based on data left in = the ring. Sonic=20 >-----Original Message----- >From: uclinux-dist-devel-bounces@blackfin.uclinux.org=20 >[mailto:uclinux-dist-devel-bounces@blackfin.uclinux.org] On=20 >Behalf Of Barry Song >Sent: Wednesday, March 03, 2010 11:26 AM >To: J.I. Cameron >Cc: linux-iio@vger.kernel.org;=20 >uclinux-dist-devel@blackfin.uclinux.org; manuel.stahl@iis.fraunhofer.de >Subject: Re: [Uclinux-dist-devel] IIO ring buffer > >DACs like=20 >AD5624R/5644R/5664R(http://www.analog.com/en/digital-to-analog- >converters/da-converters/ad5624r/products/product.html) >have no clock input and internal buffer. Some users maybe use=20 >it to get discrete analog signals, that means once one data is=20 >written to AD5624R, one new analog signal is output, then we=20 >don't need ring buffer. But some other users maybe want the=20 >AD5624R to create continuous signals with a fixed frequency,=20 >then we need use ring buffer with linked DMA to input data to=20 >AD5624R with a constant rate. >This case is same with audio play. >To implement that, we need >1. Split ring buffer to some little fragments, one fragment is=20 >a DMA block. >2. Ring buffer core layer must handle the play pointer and=20 >user writing pointer, stop the DMA automatically when user=20 >data under-run flows( valid data is less than one fragment in=20 >ring buffer) 3. The DMA interrupt handler in the bottom driver=20 >should update the play pointer by a ring buffer core API to=20 >notify the play status. >4. The DMA should support linked mode, once one DMA block is=20 >finished, another DMA fragment will be enabled by hardware=20 >automatically except that it is disabled due to underflow. >Thanks >Barry > >On Tue, Mar 2, 2010 at 6:45 PM, J.I. Cameron <jic23@cam.ac.uk> wrote: >> Hi Barry, >> >>> I know you are changing iio ring buffer. Here a problem to discuss=20 >>> with you, there are maybe this kind of use cases: the DACs have no=20 >>> internal clock and buffer, so we need an external bus with=20 >continuous=20 >>> DMA to "play" data flow with constant speed. It is very=20 >similar with=20 >>> alsa driver to play audio by I2S or AC97. ALSA framework is easy to=20 >>> implement this kind of drivers. But our DACs are not audio cards.=20 >>> Then in the iio ring buffer core, it seems we also need APIs like=20 >>> trigger(), pointer(), snd_pcm_period_elapsed()... to get a common=20 >>> framework. >> >> I have to admit I'm in general a little unclear on how one even goes=20 >> about getting dma to occur at a constant speed. =A0I'm afraid=20 >I haven't=20 >> had much time to work on improving the ring buffer (though I=20 >will try=20 >> and get a patch out for one particular bug sometime today -=20 >if you get=20 >> issues in the init function with spin locks). =A0 Hence, I=20 >suggest that=20 >> you propose any changes you would like to see in the core,=20 >if possible=20 >> with some code along side relevant data sheets so those of us not so=20 >> familiar with this area can better understand how this would work. >> >> My short term plans for the buffering is to allow use of the new=20 >> implementation of kfifo as it allows dma transfers to occur directly=20 >> into the buffer. =A0Obviously this will involve adding a few=20 >new bits to the api. >> >> That internal api is certainly far from locked in stone and=20 >as long as=20 >> we can mend any driver broken by changes, feel free to propose any=20 >> changes you like! >> >>> Of course, we can let users to handle blocking in write() callback=20 >>> like OSS, but alsa-like APIs should be better. So what's=20 >your opinion=20 >>> for that? >>> If I begin to work on this, I am not sure how much is=20 >needed to do to=20 >>> merge into your new iio ring buffer codes. So if you have some new=20 >>> codes for reference, it should be better. >> >> Sorry, no new code for now. =A0All changes in my tree are driver = based=20 >> rather than core (and right now to messy to post publicly) >> >> Looking forward to seeing what you propose in further detail. >> >> Jonathan >> >_______________________________________________ >Uclinux-dist-devel mailing list >Uclinux-dist-devel@blackfin.uclinux.org >https://blackfin.uclinux.org/mailman/listinfo/uclinux-dist-devel > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-03-03 3:26 ` Barry Song 2010-03-03 5:59 ` [Uclinux-dist-devel] " Zhang, Sonic @ 2010-03-04 12:33 ` Jonathan Cameron 2010-03-08 3:41 ` Barry Song 1 sibling, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-03-04 12:33 UTC (permalink / raw) To: Barry Song Cc: manuel.stahl, uclinux-dist-devel, linux-iio, David Brownell, Grant Likely Hi Barry, Sorry for the slow reply, been busy with the whole ALS thing (see lkml if you are interested) and chasing down some rtc issues. On 03/03/10 03:26, Barry Song wrote: > DACs like AD5624R/5644R/5664R(http://www.analog.com/en/digital-to-analog-converters/da-converters/ad5624r/products/product.html) > have no clock input and internal buffer. Some users maybe use it to > get discrete analog signals, that means once one data is written to > AD5624R, one new analog signal is output, then we don't need ring > buffer. Makes sense, I guess for these we provide a sysfs type interface. > But some other users maybe want the AD5624R to create > continuous signals with a fixed frequency, then we need use ring > buffer with linked DMA to input data to AD5624R with a constant rate. > This case is same with audio play. > To implement that, we need > 1. Split ring buffer to some little fragments, one fragment is a DMA block. Makes sense, though we probably need to be a little careful as not spi implementations are going to do this via dma. > 2. Ring buffer core layer must handle the play pointer and user > writing pointer, stop the DMA automatically when user data under-run > flows( valid data is less than one fragment in ring buffer) Probably a fifo rather than a ring buffer, but it doesn't change your point! At the moment I'm not seeing much shared functionality with the rest of IIO. Perhaps we treat DAC elements in a similar way to triggers? That is a device may register them without registering anything else. Will keep matters nice and slim if we have devices such as this one that don't have any inputs. The only disadvantage I can see is when we have interesting interactions between the dac's and inputs (such as a feedback channel). > 3. The DMA interrupt handler in the bottom driver should update the > play pointer by a ring buffer core API to notify the play status. > 4. The DMA should support linked mode, once one DMA block is > finished, another DMA fragment will be enabled by hardware > automatically except that it is disabled due to underflow. The complexity I can see here is interacting with the underlying bus. It may be that we need to propose some changes to the spi infrastructure, it order to get the hooks you are referring to. I'm really not keen in reinventing the wheel and providing bus interfaces within IIO. If we have new buses or new requirements for existing bus subsystems, we should propose them separately. They will almost certainly be of use elsewhere anyway! I've cc'd David and Grant to see if they have any initial comments on this or are aware of people doing similar stuff. (it's all a bit vague at the moment for a post to the spi mailing list). Maybe it is possible already to do this? Certainly looks like this is the first area to investigate to me. Thanks, Jonathan > > On Tue, Mar 2, 2010 at 6:45 PM, J.I. Cameron <jic23@cam.ac.uk> wrote: >> Hi Barry, >> >>> I know you are changing iio ring buffer. Here a problem to discuss >>> with you, there are maybe this kind of use cases: the DACs have no >>> internal clock and buffer, so we need an external bus with continuous >>> DMA to "play" data flow with constant speed. It is very similar with >>> alsa driver to play audio by I2S or AC97. ALSA framework is easy to >>> implement this kind of drivers. But our DACs are not audio cards. Then >>> in the iio ring buffer core, it seems we also need APIs like >>> trigger(), pointer(), snd_pcm_period_elapsed()... to get a common >>> framework. >> >> I have to admit I'm in general a little unclear on how one even goes about >> getting dma to occur at a constant speed. I'm afraid I haven't had much >> time to work on improving the ring buffer (though I will try and get a patch >> out for one particular bug sometime today - if you get issues in the init >> function with spin locks). Hence, I suggest that you propose any changes >> you would like to see in the core, if possible with some code along side >> relevant data sheets so those of us not so familiar with this area can >> better understand how this would work. >> >> My short term plans for the buffering is to allow use of the new >> implementation of kfifo as it allows dma transfers to occur directly into >> the buffer. Obviously this will involve adding a few new bits to the api. >> >> That internal api is certainly far from locked in stone and as long as we >> can mend any driver broken by changes, feel free to propose any changes you >> like! >> >>> Of course, we can let users to handle blocking in write() >>> callback like OSS, but alsa-like APIs should be better. So what's your >>> opinion for that? >>> If I begin to work on this, I am not sure how much is needed to do to >>> merge into your new iio ring buffer codes. So if you have some new >>> codes for reference, it should be better. >> >> Sorry, no new code for now. All changes in my tree are driver based rather >> than core (and right now to messy to post publicly) >> >> Looking forward to seeing what you propose in further detail. >> >> Jonathan >> ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-03-04 12:33 ` Jonathan Cameron @ 2010-03-08 3:41 ` Barry Song 2010-03-08 11:23 ` Jonathan Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-03-08 3:41 UTC (permalink / raw) To: Jonathan Cameron Cc: manuel.stahl, uclinux-dist-devel, linux-iio, David Brownell, Grant Likely On Thu, Mar 4, 2010 at 8:33 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > > Hi Barry, > > Sorry for the slow reply, been busy with the whole ALS thing > (see lkml if you are interested) and chasing down some rtc issues. > > On 03/03/10 03:26, Barry Song wrote: > > DACs like AD5624R/5644R/5664R(http://www.analog.com/en/digital-to-analo= g-converters/da-converters/ad5624r/products/product.html) > > have no clock input and internal buffer. Some users maybe use it to > > get discrete analog signals, that means once one data is written to > > AD5624R, one new analog signal is output, then we don't need ring > > buffer. > Makes sense, I guess for these we provide a sysfs type interface. > > But some other users maybe want the AD5624R to create > > continuous signals with a fixed frequency, then we need use ring > > buffer with linked DMA to input data to AD5624R with a constant rate. > > This case is same with audio play. > > To implement that, we need > > 1. Split ring buffer to some little fragments, one fragment is a DMA bl= ock. > Makes sense, though we probably need to be a little careful > as not spi implementations are going to do this via dma. > > 2. Ring buffer core layer must handle the play pointer and user > > writing pointer, stop the DMA automatically when user data under-run > > flows( valid data is less than one fragment in ring buffer) > Probably a fifo rather than a ring buffer, but it doesn't change your > point! At the moment I'm not seeing much shared functionality with the > rest of IIO. =C2=A0Perhaps we treat DAC elements in a similar way to trig= gers? > That is a device may register them without registering anything else. > Will keep matters nice and slim if we have devices such as this one that > don't have any inputs. =C2=A0The only disadvantage I can see is when we h= ave > interesting interactions between the dac's and inputs (such as a feedback > channel). It should be a hardware ring buffer because we must have allocated it by consistent way ahead. The buffer has been ready and DMA link has been built when we begin any transfer. Sorry, i don't understand clearly about treating DACs as trigggers you said, here i think we only need interrupts/callbacks to update playback pointers. > > > 3. The DMA interrupt handler in the bottom driver should update the > > play pointer by a ring buffer core API to notify the play status. > > 4. The DMA should support =C2=A0linked mode, once one DMA block is > > finished, another DMA fragment will be enabled by hardware > > automatically except that it is disabled due to underflow. > The complexity I can see here is interacting with the underlying bus. > It may be that we need to propose some changes to the spi infrastructure, > it order to get the hooks you are referring to. =C2=A0I'm really not keen= in > reinventing the wheel and providing bus interfaces within IIO. > If we have new buses or new requirements for existing bus subsystems, > we should propose them separately. They will almost certainly be of use > elsewhere anyway! It maybe makes sense too to change current spi drivers. spi async mode can help if we change blackfin sport spi driver(http://blackfin.uclinux.org/gf/project/linux-kernel/scmsvn/?action= =3Dbrowse&path=3D%2Ftrunk%2Fdrivers%2Fspi%2Fbfin_sport_spi.c&view=3Dmarkup&= revision=3D8051) to use linked DMA. DAC drivers only call spi_async and use the spi completion callback to update playback pointer. And sport spi driver manages the DMA link and keep the spi acccess running if there are still spi messages. The performance should be better if current spi can be improved to support block mode but not manage spi transfer by single spi message. The same problem will happen to i2c bus if there are similar DACs using i2c= bus. > > I've cc'd David and Grant to see if they have any initial comments on > this or are aware of people doing similar stuff. =C2=A0(it's all a bit > vague at the moment for a post to the spi mailing list). =C2=A0Maybe > it is possible already to do this? =C2=A0Certainly looks like this is the > first area to investigate to me. > > Thanks, > > Jonathan > > > > > > On Tue, Mar 2, 2010 at 6:45 PM, J.I. Cameron <jic23@cam.ac.uk> wrote: > >> Hi Barry, > >> > >>> I know you are changing iio ring buffer. Here a problem to discuss > >>> with you, there are maybe this kind of use cases: the DACs have no > >>> internal clock and buffer, so we need an external bus with continuous > >>> DMA to "play" data flow with constant speed. It is very similar with > >>> alsa driver to play audio by I2S or AC97. ALSA framework is easy to > >>> implement this kind of drivers. But our DACs are not audio cards. The= n > >>> in the iio ring buffer core, it seems we also need APIs like > >>> trigger(), pointer(), snd_pcm_period_elapsed()... to get a common > >>> framework. > >> > >> I have to admit I'm in general a little unclear on how one even goes a= bout > >> getting dma to occur at a constant speed. =C2=A0I'm afraid I haven't h= ad much > >> time to work on improving the ring buffer (though I will try and get a= patch > >> out for one particular bug sometime today - if you get issues in the i= nit > >> function with spin locks). =C2=A0 Hence, I suggest that you propose an= y changes > >> you would like to see in the core, if possible with some code along si= de > >> relevant data sheets so those of us not so familiar with this area can > >> better understand how this would work. > >> > >> My short term plans for the buffering is to allow use of the new > >> implementation of kfifo as it allows dma transfers to occur directly i= nto > >> the buffer. =C2=A0Obviously this will involve adding a few new bits to= the api. > >> > >> That internal api is certainly far from locked in stone and as long as= we > >> can mend any driver broken by changes, feel free to propose any change= s you > >> like! > >> > >>> Of course, we can let users to handle blocking in write() > >>> callback like OSS, but alsa-like APIs should be better. So what's you= r > >>> opinion for that? > >>> If I begin to work on this, I am not sure how much is needed to do to > >>> merge into your new iio ring buffer codes. So if you have some new > >>> codes for reference, it should be better. > >> > >> Sorry, no new code for now. =C2=A0All changes in my tree are driver ba= sed rather > >> than core (and right now to messy to post publicly) > >> > >> Looking forward to seeing what you propose in further detail. > >> > >> Jonathan > >> > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: IIO ring buffer 2010-03-08 3:41 ` Barry Song @ 2010-03-08 11:23 ` Jonathan Cameron 0 siblings, 0 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-03-08 11:23 UTC (permalink / raw) To: Barry Song Cc: manuel.stahl, uclinux-dist-devel, linux-iio, David Brownell, Grant Likely On 03/08/10 03:41, Barry Song wrote: > On Thu, Mar 4, 2010 at 8:33 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> >> Hi Barry, >> >> Sorry for the slow reply, been busy with the whole ALS thing >> (see lkml if you are interested) and chasing down some rtc issues. >> >> On 03/03/10 03:26, Barry Song wrote: >>> DACs like AD5624R/5644R/5664R(http://www.analog.com/en/digital-to-analog-converters/da-converters/ad5624r/products/product.html) >>> have no clock input and internal buffer. Some users maybe use it to >>> get discrete analog signals, that means once one data is written to >>> AD5624R, one new analog signal is output, then we don't need ring >>> buffer. >> Makes sense, I guess for these we provide a sysfs type interface. >>> But some other users maybe want the AD5624R to create >>> continuous signals with a fixed frequency, then we need use ring >>> buffer with linked DMA to input data to AD5624R with a constant rate. >>> This case is same with audio play. >>> To implement that, we need >>> 1. Split ring buffer to some little fragments, one fragment is a DMA block. >> Makes sense, though we probably need to be a little careful >> as not spi implementations are going to do this via dma. >>> 2. Ring buffer core layer must handle the play pointer and user >>> writing pointer, stop the DMA automatically when user data under-run >>> flows( valid data is less than one fragment in ring buffer) >> Probably a fifo rather than a ring buffer, but it doesn't change your >> point! At the moment I'm not seeing much shared functionality with the >> rest of IIO. Perhaps we treat DAC elements in a similar way to triggers? >> That is a device may register them without registering anything else. >> Will keep matters nice and slim if we have devices such as this one that >> don't have any inputs. The only disadvantage I can see is when we have >> interesting interactions between the dac's and inputs (such as a feedback >> channel). > It should be a hardware ring buffer because we must have allocated it > by consistent way ahead. The buffer has been ready and DMA link has > been built when we begin any transfer. Sorry, i don't understand > clearly about treating DACs as trigggers you said, here i think we > only need interrupts/callbacks to update playback pointers. I simply meant that one can treat them as effectively independant from the core iio_device structures seeing as there is almost no shared functionality. Thus a driver can register any of: iio_device (we may need to rename!), iio_trigger and iio_dac. In a similar way to the triggers a dac might be a child of an iio_device, but also might exist on it's own if none of the other functionality is needed (i.e. it is just a dac). >> >>> 3. The DMA interrupt handler in the bottom driver should update the >>> play pointer by a ring buffer core API to notify the play status. >>> 4. The DMA should support linked mode, once one DMA block is >>> finished, another DMA fragment will be enabled by hardware >>> automatically except that it is disabled due to underflow. >> The complexity I can see here is interacting with the underlying bus. >> It may be that we need to propose some changes to the spi infrastructure, >> it order to get the hooks you are referring to. I'm really not keen in >> reinventing the wheel and providing bus interfaces within IIO. >> If we have new buses or new requirements for existing bus subsystems, >> we should propose them separately. They will almost certainly be of use >> elsewhere anyway! > It maybe makes sense too to change current spi drivers. spi async mode > can help if we change blackfin sport spi > driver(http://blackfin.uclinux.org/gf/project/linux-kernel/scmsvn/?action=browse&path=%2Ftrunk%2Fdrivers%2Fspi%2Fbfin_sport_spi.c&view=markup&revision=8051) > to use linked DMA. DAC drivers only call spi_async and use the spi > completion callback to update playback pointer. And sport spi driver > manages the DMA link and keep the spi acccess running if there are > still spi messages. That sounds sensible (though I haven't looked at the specifics). If possible make sure you maintain support for devices not capable of using linked dma though. I would suggest putting together an example and proposing some suitable interfaces to be added to the spi core (we can tackle other buses as they come up!) > The performance should be better if current spi can be improved to > support block mode but not manage spi transfer by single spi message. > The same problem will happen to i2c bus if there are similar DACs using i2c bus. >> >> I've cc'd David and Grant to see if they have any initial comments on >> this or are aware of people doing similar stuff. (it's all a bit >> vague at the moment for a post to the spi mailing list). Maybe >> it is possible already to do this? Certainly looks like this is the >> first area to investigate to me. >> >> Thanks, >> >> Jonathan >> >> >>> >>> On Tue, Mar 2, 2010 at 6:45 PM, J.I. Cameron <jic23@cam.ac.uk> wrote: >>>> Hi Barry, >>>> >>>>> I know you are changing iio ring buffer. Here a problem to discuss >>>>> with you, there are maybe this kind of use cases: the DACs have no >>>>> internal clock and buffer, so we need an external bus with continuous >>>>> DMA to "play" data flow with constant speed. It is very similar with >>>>> alsa driver to play audio by I2S or AC97. ALSA framework is easy to >>>>> implement this kind of drivers. But our DACs are not audio cards. Then >>>>> in the iio ring buffer core, it seems we also need APIs like >>>>> trigger(), pointer(), snd_pcm_period_elapsed()... to get a common >>>>> framework. >>>> >>>> I have to admit I'm in general a little unclear on how one even goes about >>>> getting dma to occur at a constant speed. I'm afraid I haven't had much >>>> time to work on improving the ring buffer (though I will try and get a patch >>>> out for one particular bug sometime today - if you get issues in the init >>>> function with spin locks). Hence, I suggest that you propose any changes >>>> you would like to see in the core, if possible with some code along side >>>> relevant data sheets so those of us not so familiar with this area can >>>> better understand how this would work. >>>> >>>> My short term plans for the buffering is to allow use of the new >>>> implementation of kfifo as it allows dma transfers to occur directly into >>>> the buffer. Obviously this will involve adding a few new bits to the api. >>>> >>>> That internal api is certainly far from locked in stone and as long as we >>>> can mend any driver broken by changes, feel free to propose any changes you >>>> like! >>>> >>>>> Of course, we can let users to handle blocking in write() >>>>> callback like OSS, but alsa-like APIs should be better. So what's your >>>>> opinion for that? >>>>> If I begin to work on this, I am not sure how much is needed to do to >>>>> merge into your new iio ring buffer codes. So if you have some new >>>>> codes for reference, it should be better. >>>> >>>> Sorry, no new code for now. All changes in my tree are driver based rather >>>> than core (and right now to messy to post publicly) >>>> >>>> Looking forward to seeing what you propose in further detail. >>>> >>>> Jonathan >>>> >> ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-02-22 11:16 ` IIO ring buffer Jonathan Cameron 2010-02-23 4:11 ` Song, Barry @ 2010-06-02 8:01 ` Barry Song 2010-06-02 13:21 ` Jonathan Cameron 1 sibling, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-02 8:01 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On Mon, Feb 22, 2010 at 7:16 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > Hi All, > > Just for reference as I'll be doing a proper announcement later. > We now have linux-iio@vger.kernel.org as a mailing list for the project. > Unless others have tracked it down it currently only has me as a member > though and I'm waiting for confirmation from marc.info of an archive. > >> Hi Jonathan, >> Now users depend on iio ring events(IIO_EVENT_CODE_RING_50/75/100_FULL) >> to read data: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D fr= ead(&dat, 1, sizeof(struct >> iio_event_data), >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fp_ev); >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (dat.id) = { >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT_C= ODE_RING_100_FULL: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT_C= ODE_RING_75_FULL: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength*3/4; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT_C= ODE_RING_50_FULL: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength/2; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 default: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 printf("Unexpecteded event code\n"); >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 continue; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D re= ad(fp, >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data, >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0toread*size_from_scanmode(N= umVals, >> scan_ts)); >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (read_size = =3D=3D -EAGAIN) { >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 printf("nothing available \n"); >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 continue; >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >> And iio ring access node doesn't support blocking io too. =C2=A0It seems= we >> lost to let users read data once ring is not empty. And some users maybe >> not care about iio ring events at all, but just want to read data like a >> input or audio driver. So how about adding the following support in iio >> ring: >> 1. add NOT EMPTY event in IIO event nodes > Not keen. =C2=A0It might lead to a storm of events (at least it might in = a > cleverer ring buffer implementation or during a blocking read). =C2=A0Act= ually > in this particular case it probably wouldn't do any harm. >> 2. add blocking io support in read function of IIO access nodes > That I agree would be a good idea. =C2=A0If we support poll/select on the= buffer access > chrdev then we will get the same effect per having a not empty event and = cleaner > semantics for anyone not interested in the other events. Not to mention I= expect > we will soon have alternative ring buffer implementations that don't supp= ly any > events at all and hence don't event have the relevant chrdev. > > As things are, you can quite happily read whenever you like. =C2=A0Now yo= u mention it, > that example code is somewhat missleading! The issue with > this ring buffer implementation is the handling of a true blocking read i= s complex > as at any given time you aren't guaranteed to get what you asked for even= if it was > there when you started the read. It should be possible to work around tha= t though. > > It's possible this functionality might be better added to an alternative = ring buffer > implementation. Be vary wary of that ring implementation in general! I am= and I wrote it. >> If you agree with that, I can begin to add these and send you a patch. >> And a problem I don't know is what you and other people have changed to >> Greg's staging tree, and I am not sure what tree the patch should be >> againest. > Nothing has changed in this region of the code. =C2=A0In fact I think all= that > has gone into Greg's tree is a clean up patch form Mark Brown making a fe= w > functions static. Right now I'm still getting the max1363 driver into > a state where it will be possible to do the ABI changes. >> >> For long term plan, is it possible for ring common level to handle more >> common work to avoid code repeating in different drivers? > I'm certainly happy for that to be the case if it becomes apparent which = functionality > is shared. =C2=A0I haven't seen any substantial cases as yet, but then I = may well be missing > things so feel free to submit suggestions (or as ever the better option o= f patches). Now we have many drivers using SW ring with same preenable(),postenable(),predisable(), initialize_ring(),uninitialize_ring(),poll_func(),probe_trigger(), remove_trigger(). Can we move them to IIO common layer as a base class methods. And the derived class can overload them if they have special implement? Most devices just use the common layer and don't need to copy codes. > > Thanks, > > Jonathan > > _______________________________________________ > Uclinux-dist-devel mailing list > Uclinux-dist-devel@blackfin.uclinux.org > https://blackfin.uclinux.org/mailman/listinfo/uclinux-dist-devel > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-02 8:01 ` [Uclinux-dist-devel] " Barry Song @ 2010-06-02 13:21 ` Jonathan Cameron 2010-06-10 4:48 ` Barry Song 0 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-06-02 13:21 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/02/10 09:01, Barry Song wrote: > On Mon, Feb 22, 2010 at 7:16 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> Hi All, >> >> Just for reference as I'll be doing a proper announcement later. >> We now have linux-iio@vger.kernel.org as a mailing list for the project. >> Unless others have tracked it down it currently only has me as a member >> though and I'm waiting for confirmation from marc.info of an archive. >> >>> Hi Jonathan, >>> Now users depend on iio ring events(IIO_EVENT_CODE_RING_50/75/100_FULL) >>> to read data: >>> read_size = fread(&dat, 1, sizeof(struct >>> iio_event_data), >>> fp_ev); >>> switch (dat.id) { >>> case IIO_EVENT_CODE_RING_100_FULL: >>> toread = RingLength; >>> break; >>> case IIO_EVENT_CODE_RING_75_FULL: >>> toread = RingLength*3/4; >>> break; >>> case IIO_EVENT_CODE_RING_50_FULL: >>> toread = RingLength/2; >>> break; >>> default: >>> printf("Unexpecteded event code\n"); >>> continue; >>> } >>> read_size = read(fp, >>> data, >>> toread*size_from_scanmode(NumVals, >>> scan_ts)); >>> if (read_size == -EAGAIN) { >>> printf("nothing available \n"); >>> continue; >>> } >>> And iio ring access node doesn't support blocking io too. It seems we >>> lost to let users read data once ring is not empty. And some users maybe >>> not care about iio ring events at all, but just want to read data like a >>> input or audio driver. So how about adding the following support in iio >>> ring: >>> 1. add NOT EMPTY event in IIO event nodes >> Not keen. It might lead to a storm of events (at least it might in a >> cleverer ring buffer implementation or during a blocking read). Actually >> in this particular case it probably wouldn't do any harm. >>> 2. add blocking io support in read function of IIO access nodes >> That I agree would be a good idea. If we support poll/select on the buffer access >> chrdev then we will get the same effect per having a not empty event and cleaner >> semantics for anyone not interested in the other events. Not to mention I expect >> we will soon have alternative ring buffer implementations that don't supply any >> events at all and hence don't event have the relevant chrdev. >> >> As things are, you can quite happily read whenever you like. Now you mention it, >> that example code is somewhat missleading! The issue with >> this ring buffer implementation is the handling of a true blocking read is complex >> as at any given time you aren't guaranteed to get what you asked for even if it was >> there when you started the read. It should be possible to work around that though. >> >> It's possible this functionality might be better added to an alternative ring buffer >> implementation. Be vary wary of that ring implementation in general! I am and I wrote it. >>> If you agree with that, I can begin to add these and send you a patch. >>> And a problem I don't know is what you and other people have changed to >>> Greg's staging tree, and I am not sure what tree the patch should be >>> againest. >> Nothing has changed in this region of the code. In fact I think all that >> has gone into Greg's tree is a clean up patch form Mark Brown making a few >> functions static. Right now I'm still getting the max1363 driver into >> a state where it will be possible to do the ABI changes. >>> >>> For long term plan, is it possible for ring common level to handle more >>> common work to avoid code repeating in different drivers? >> I'm certainly happy for that to be the case if it becomes apparent which functionality >> is shared. I haven't seen any substantial cases as yet, but then I may well be missing >> things so feel free to submit suggestions (or as ever the better option of patches). > > Now we have many drivers using SW ring with same > preenable(),postenable(),predisable(), > initialize_ring(),uninitialize_ring(),poll_func(),probe_trigger(), > remove_trigger(). Can we move them to IIO common layer as a base class > methods. And the derived class can overload them if they have special > implement? Most devices just use the common layer and don't need to > copy codes. Sounds sensible. Please propose a patch. Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-02 13:21 ` Jonathan Cameron @ 2010-06-10 4:48 ` Barry Song 2010-06-10 4:51 ` Barry Song ` (2 more replies) 0 siblings, 3 replies; 31+ messages in thread From: Barry Song @ 2010-06-10 4:48 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 Just RFC for discussion. It is not the last patch To keep the change lest, i extract the common factor for most iio devices to a common ring trigger module. Most devices can use the interfaces in this module directly. So copy-paste for ring and trigger is not necessary now. For iio core changes: 1. extract xxx_state to iio_state and add a private data to contain chip-specific data 2. extract all xxx_ring/xxx_trigger api to common api Index: drivers/staging/iio/iio.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/iio.h (revision 8893) +++ drivers/staging/iio/iio.h (working copy) @@ -447,4 +447,46 @@ int iio_get_new_idr_val(struct idr *this_idr); void iio_free_idr_val(struct idr *this_idr, int id); + +/** + * struct iio_state - hardware level hooks for iio device + * @work_trigger_to_ring: bh for triggered event handling + * @work_cont_thresh: CLEAN + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + * @irq: interrupt number + * @set_irq: control the disable/enable of external interrupt + * @hw_read_ring: read ring data from hardware by spi/i2c. + **/ +struct iio_state { + struct device *parent_dev; + struct work_struct work_trigger_to_ring; + struct iio_work_cont work_cont_thresh; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; + int irq; + int (*set_irq)(struct iio_state *st, bool enable); + int (*hw_read_ring)(struct iio_state *st, u8 *rx); + void *priv; +}; + +static inline void iio_state_set_privdata(struct iio_state *st, void *data= ) +{ + st->priv =3D data; +} + +static inline void * iio_state_get_privdata(struct iio_state *st) +{ + return st->priv; +} + #endif /* _INDUSTRIAL_IO_H_ */ Index: drivers/staging/iio/common-ring-trigger.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/common-ring-trigger.c (revision 0) +++ drivers/staging/iio/common-ring-trigger.c (revision 0) @@ -0,0 +1,277 @@ +/* The software ring with trigger which can be used by most drivers + * + * Copyright (c) 2010 Barry Song + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as publishe= d by + * the Free Software Foundation. + * + */ +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/module.h> +#include <linux/cdev.h> +#include <linux/slab.h> + +#include "iio.h" +#include "ring_generic.h" +#include "trigger.h" +#include "ring_sw.h" + +/* + * combine_8_to_16(): utility function to munge to u8s into u16 + */ +static inline u16 combine_8_to_16(u8 lower, u8 upper) +{ + u16 _lower =3D lower; + u16 _upper =3D upper; + return _lower | (_upper << 8); +} + +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) +{ + struct iio_state *st =3D iio_dev_get_devdata(indio_dev); + st->last_timestamp =3D indio_dev->trig->timestamp; + schedule_work(&st->work_trigger_to_ring); +} + +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct iio_state *st + =3D container_of(work_s, struct iio_state, + work_trigger_to_ring); + + int i =3D 0; + s16 *data; + size_t datasize =3D st->indio_dev + ->ring->access.get_bpd(st->indio_dev->ring); + + data =3D kmalloc(datasize , GFP_KERNEL); + if (data =3D=3D NULL) { + dev_err(st->parent_dev, "memory alloc failed in ring bh"); + return; + } + + if (st->indio_dev->scan_count) + if (st->hw_read_ring(st, st->rx) >=3D 0) + for (; i < st->indio_dev->scan_count; i++) { + data[i] =3D combine_8_to_16(st->rx[i*2+1], + st->rx[i*2]); + } + + /* Guaranteed to be aligned with 8 byte boundary */ + if (st->indio_dev->scan_timestamp) + *((s64 *)(data + ((i + 3)/4)*4)) =3D st->last_timestamp; + + st->indio_dev->ring->access.store_to(st->indio_dev->ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} + +static int iio_common_ring_preenable(struct iio_dev *indio_dev) +{ + size_t size; + dev_dbg(&indio_dev->dev, "%s\n", __func__); + /* Check if there are any scan elements enabled, if not fail*/ + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) + return -EINVAL; + + if (indio_dev->ring->access.set_bpd) { + if (indio_dev->scan_timestamp) + if (indio_dev->scan_count) + /* Timestamp (aligned to s64) and data */ + size =3D (((indio_dev->scan_count * sizeof(s16)) + + sizeof(s64) - 1) + & ~(sizeof(s64) - 1)) + + sizeof(s64); + else /* Timestamp only */ + size =3D sizeof(s64); + else /* Data only */ + size =3D indio_dev->scan_count*sizeof(s16); + indio_dev->ring->access.set_bpd(indio_dev->ring, size); + } + + return 0; +} + +static int iio_common_ring_postenable(struct iio_dev *indio_dev) +{ + return indio_dev->trig + ? iio_trigger_attach_poll_func(indio_dev->trig, + indio_dev->pollfunc) + : 0; +} + +static int iio_common_ring_predisable(struct iio_dev *indio_dev) +{ + return indio_dev->trig + ? iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc) + : 0; +} + +int iio_configure_common_ring(struct iio_dev *indio_dev) +{ + int ret =3D 0; + struct iio_state *st =3D indio_dev->dev_data; + struct iio_ring_buffer *ring; + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); + + ring =3D iio_sw_rb_allocate(indio_dev); + if (!ring) { + ret =3D -ENOMEM; + return ret; + } + indio_dev->ring =3D ring; + + iio_ring_sw_register_funcs(&ring->access); + ring->preenable =3D &iio_common_ring_preenable; + ring->postenable =3D &iio_common_ring_postenable; + ring->predisable =3D &iio_common_ring_predisable; + ring->owner =3D THIS_MODULE; + + indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL)= ; + if (indio_dev->pollfunc =3D=3D NULL) { + ret =3D -ENOMEM; + goto error_iio_sw_rb_free;; + } + indio_dev->pollfunc->poll_func_main =3D &iio_common_ring_poll_func_th; + indio_dev->pollfunc->private_data =3D indio_dev; + indio_dev->modes |=3D INDIO_RING_TRIGGERED; + return 0; + +error_iio_sw_rb_free: + iio_sw_rb_free(indio_dev->ring); + return ret; +} +EXPORT_SYMBOL(iio_configure_common_ring); + +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) +{ + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} +EXPORT_SYMBOL(iio_unconfigure_common_ring); + +int iio_initialize_common_ring(struct iio_ring_buffer *ring) +{ + return iio_ring_buffer_register(ring, 0); +} +EXPORT_SYMBOL(iio_initialize_common_ring); + +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) +{ + iio_ring_buffer_unregister(ring); +} +EXPORT_SYMBOL(iio_uninitialize_common_ring); + +static int iio_common_trigger_poll(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct iio_state *st =3D iio_dev_get_devdata(dev_info); + struct iio_trigger *trig =3D st->trig; + + trig->timestamp =3D timestamp; + iio_trigger_poll(trig); + + return IRQ_HANDLED; +} + +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); + +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *iio_trigger_attrs[] =3D { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group iio_trigger_attr_group =3D { + .attrs =3D iio_trigger_attrs, +}; + +static int iio_common_trigger_try_reen(struct iio_trigger *trig) +{ + struct iio_state *st =3D trig->private_data; + enable_irq(st->irq); + return 0; +} + +static int iio_common_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_state *st =3D trig->private_data; + struct iio_dev *indio_dev =3D st->indio_dev; + int ret =3D 0; + + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + ret =3D st->set_irq(st, state); + if (state =3D=3D false) { + iio_remove_event_from_list(&iio_event_common_trig, + &indio_dev->interrupts[0] + ->ev_list); + flush_scheduled_work(); + } else { + iio_add_event_to_list(&iio_event_common_trig, + &indio_dev->interrupts[0]->ev_list); + } + return ret; +} + +int iio_probe_common_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct iio_state *st =3D indio_dev->dev_data; + + st->trig =3D iio_allocate_trigger(); + st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + if (!st->trig->name) { + ret =3D -ENOMEM; + goto error_free_trig; + } + snprintf((char *)st->trig->name, + IIO_TRIGGER_NAME_LENGTH, + "iio-dev%d", indio_dev->id); + st->trig->dev.parent =3D st->parent_dev; + st->trig->owner =3D THIS_MODULE; + st->trig->private_data =3D st; + st->trig->set_trigger_state =3D &iio_common_trigger_set_state; + st->trig->try_reenable =3D &iio_common_trigger_try_reen; + st->trig->control_attrs =3D &iio_trigger_attr_group; + ret =3D iio_trigger_register(st->trig); + + /* select default trigger */ + indio_dev->trig =3D st->trig; + if (ret) + goto error_free_trig_name; + + return 0; + +error_free_trig_name: + kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + + return ret; +} +EXPORT_SYMBOL(iio_probe_common_trigger); + +void iio_remove_common_trigger(struct iio_dev *indio_dev) +{ + struct iio_state *state =3D indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} +EXPORT_SYMBOL(iio_remove_common_trigger); Index: drivers/staging/iio/common-ring-trigger.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/common-ring-trigger.h (revision 0) +++ drivers/staging/iio/common-ring-trigger.h (revision 0) @@ -0,0 +1,24 @@ +/* The industrial I/O frequently used ring with trigger + * + * Copyright (c) 2010 Barry Song + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as publishe= d by + * the Free Software Foundation. + * + */ + +#ifndef _IIO_COMMON_RING_TRIGGER_H_ +#define _IIO_COMMON_RING_TRIGGER_H_ + +#include "iio.h" +#include "ring_generic.h" + +int iio_configure_common_ring(struct iio_dev *indio_dev); +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); +int iio_initialize_common_ring(struct iio_ring_buffer *ring); +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); + +int iio_probe_common_trigger(struct iio_dev *indio_dev); +void iio_remove_common_trigger(struct iio_dev *indio_dev); +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ Index: drivers/staging/iio/Kconfig =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/Kconfig (revision 8893) +++ drivers/staging/iio/Kconfig (working copy) @@ -38,6 +38,12 @@ ring buffers. The triggers are effectively a 'capture data now' interrupt. +config IIO_COMMON_RING_TRIGGER + boolean "Enable frequently used ring with trigger" + depends on IIO_SW_RING && IIO_TRIGGER + help + Provides a generic ring with trigger. I can be used by most + IIO devices. source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" Index: drivers/staging/iio/Makefile =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/Makefile (revision 8893) +++ drivers/staging/iio/Makefile (working copy) @@ -9,6 +9,8 @@ obj-$(CONFIG_IIO_SW_RING) +=3D ring_sw.o +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) +=3D common-ring-trigger.o + obj-y +=3D accel/ obj-y +=3D adc/ obj-y +=3D addac/ On Wed, Jun 2, 2010 at 9:21 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 06/02/10 09:01, Barry Song wrote: >> On Mon, Feb 22, 2010 at 7:16 PM, Jonathan Cameron <jic23@cam.ac.uk> wrot= e: >>> Hi All, >>> >>> Just for reference as I'll be doing a proper announcement later. >>> We now have linux-iio@vger.kernel.org as a mailing list for the project= . >>> Unless others have tracked it down it currently only has me as a member >>> though and I'm waiting for confirmation from marc.info of an archive. >>> >>>> Hi Jonathan, >>>> Now users depend on iio ring events(IIO_EVENT_CODE_RING_50/75/100_FULL= ) >>>> to read data: >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D = fread(&dat, 1, sizeof(struct >>>> iio_event_data), >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fp_ev); >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (dat.id= ) { >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT= _CODE_RING_100_FULL: >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT= _CODE_RING_75_FULL: >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength*3/4; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVENT= _CODE_RING_50_FULL: >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 toread =3D RingLength/2; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 break; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 default: >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 printf("Unexpecteded event code\n"); >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 continue; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D = read(fp, >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data, >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0toread*size_from_scanmode(N= umVals, >>>> scan_ts)); >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (read_size = =3D=3D -EAGAIN) { >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 printf("nothing available \n"); >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 continue; >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>> And iio ring access node doesn't support blocking io too. =C2=A0It see= ms we >>>> lost to let users read data once ring is not empty. And some users may= be >>>> not care about iio ring events at all, but just want to read data like= a >>>> input or audio driver. So how about adding the following support in ii= o >>>> ring: >>>> 1. add NOT EMPTY event in IIO event nodes >>> Not keen. =C2=A0It might lead to a storm of events (at least it might i= n a >>> cleverer ring buffer implementation or during a blocking read). =C2=A0A= ctually >>> in this particular case it probably wouldn't do any harm. >>>> 2. add blocking io support in read function of IIO access nodes >>> That I agree would be a good idea. =C2=A0If we support poll/select on t= he buffer access >>> chrdev then we will get the same effect per having a not empty event an= d cleaner >>> semantics for anyone not interested in the other events. Not to mention= I expect >>> we will soon have alternative ring buffer implementations that don't su= pply any >>> events at all and hence don't event have the relevant chrdev. >>> >>> As things are, you can quite happily read whenever you like. =C2=A0Now = you mention it, >>> that example code is somewhat missleading! The issue with >>> this ring buffer implementation is the handling of a true blocking read= is complex >>> as at any given time you aren't guaranteed to get what you asked for ev= en if it was >>> there when you started the read. It should be possible to work around t= hat though. >>> >>> It's possible this functionality might be better added to an alternativ= e ring buffer >>> implementation. Be vary wary of that ring implementation in general! I = am and I wrote it. >>>> If you agree with that, I can begin to add these and send you a patch. >>>> And a problem I don't know is what you and other people have changed t= o >>>> Greg's staging tree, and I am not sure what tree the patch should be >>>> againest. >>> Nothing has changed in this region of the code. =C2=A0In fact I think a= ll that >>> has gone into Greg's tree is a clean up patch form Mark Brown making a = few >>> functions static. Right now I'm still getting the max1363 driver into >>> a state where it will be possible to do the ABI changes. >>>> >>>> For long term plan, is it possible for ring common level to handle mor= e >>>> common work to avoid code repeating in different drivers? >>> I'm certainly happy for that to be the case if it becomes apparent whic= h functionality >>> is shared. =C2=A0I haven't seen any substantial cases as yet, but then = I may well be missing >>> things so feel free to submit suggestions (or as ever the better option= of patches). >> >> Now we have many drivers using SW ring with same >> preenable(),postenable(),predisable(), >> initialize_ring(),uninitialize_ring(),poll_func(),probe_trigger(), >> remove_trigger(). Can we move them to IIO common layer as a base class >> methods. And the derived class can overload them if they have special >> implement? Most devices just use the common layer and don't need to >> copy codes. > Sounds sensible. Please propose a patch. > > Jonathan > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-10 4:48 ` Barry Song @ 2010-06-10 4:51 ` Barry Song 2010-06-10 13:48 ` Jonathan Cameron 2010-06-25 17:18 ` Jonathan Cameron 2 siblings, 0 replies; 31+ messages in thread From: Barry Song @ 2010-06-10 4:51 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 An example(adis16209) to use the new ring/trigger: 1. adis16209_ring.c and adis16209_trigger.c are not necessary and use commo= n api 2. provide callback for set_irq and hw_read_ring to common ring/trigger mod= ule Index: drivers/staging/iio/accel/adis16209_ring.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/accel/adis16209_ring.c (revision 8893) +++ drivers/staging/iio/accel/adis16209_ring.c (working copy) @@ -1,267 +0,0 @@ -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/gpio.h> -#include <linux/workqueue.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/list.h> - -#include "../iio.h" -#include "../sysfs.h" -#include "../ring_sw.h" -#include "accel.h" -#include "../trigger.h" -#include "adis16209.h" - -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower =3D lower; - u16 _upper =3D upper; - return _lower | (_upper << 8); -} - -static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14), - ADIS16209_SUPPLY_OUT, NULL); -static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14), - ADIS16209_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, IIO_SIGNED(14), - ADIS16209_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(aux_adc, ADIS16209_SCAN_AUX_ADC, IIO_UNSIGNED(12), - ADIS16209_AUX_ADC, NULL); -static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, IIO_UNSIGNED(12), - ADIS16209_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, IIO_SIGNED(14), - ADIS16209_XINCL_OUT, NULL); -static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, IIO_SIGNED(14), - ADIS16209_YINCL_OUT, NULL); -static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, IIO_SIGNED(14), - ADIS16209_ROT_OUT, NULL); - -static IIO_SCAN_EL_TIMESTAMP(8); - -static struct attribute *adis16209_scan_el_attrs[] =3D { - &iio_scan_el_supply.dev_attr.attr, - &iio_scan_el_accel_x.dev_attr.attr, - &iio_scan_el_accel_y.dev_attr.attr, - &iio_scan_el_aux_adc.dev_attr.attr, - &iio_scan_el_temp.dev_attr.attr, - &iio_scan_el_incli_x.dev_attr.attr, - &iio_scan_el_incli_y.dev_attr.attr, - &iio_scan_el_rot.dev_attr.attr, - &iio_scan_el_timestamp.dev_attr.attr, - NULL, -}; - -static struct attribute_group adis16209_scan_el_group =3D { - .attrs =3D adis16209_scan_el_attrs, - .name =3D "scan_elements", -}; - -/** - * adis16209_poll_func_th() top half interrupt handler called by trigger - * @private_data: iio_dev - **/ -static void adis16209_poll_func_th(struct iio_dev *indio_dev) -{ - struct adis16209_state *st =3D iio_dev_get_devdata(indio_dev); - st->last_timestamp =3D indio_dev->trig->timestamp; - schedule_work(&st->work_trigger_to_ring); -} - -/** - * adis16209_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_tri= g) - * @rx: somewhere to pass back the value read - **/ -static int adis16209_read_ring_data(struct device *dev, u8 *rx) -{ - struct spi_message msg; - struct iio_dev *indio_dev =3D dev_get_drvdata(dev); - struct adis16209_state *st =3D iio_dev_get_devdata(indio_dev); - struct spi_transfer xfers[ADIS16209_OUTPUTS + 1]; - int ret; - int i; - - mutex_lock(&st->buf_lock); - - spi_message_init(&msg); - - memset(xfers, 0, sizeof(xfers)); - for (i =3D 0; i <=3D ADIS16209_OUTPUTS; i++) { - xfers[i].bits_per_word =3D 8; - xfers[i].cs_change =3D 1; - xfers[i].len =3D 2; - xfers[i].delay_usecs =3D 30; - xfers[i].tx_buf =3D st->tx + 2 * i; - st->tx[2 * i] - =3D ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i); - st->tx[2 * i + 1] =3D 0; - if (i >=3D 1) - xfers[i].rx_buf =3D rx + 2 * (i - 1); - spi_message_add_tail(&xfers[i], &msg); - } - - ret =3D spi_sync(st->us, &msg); - if (ret) - dev_err(&st->us->dev, "problem when burst reading"); - - mutex_unlock(&st->buf_lock); - - return ret; -} - -/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to de= vice - * specific to be rolled into the core. - */ -static void adis16209_trigger_bh_to_ring(struct work_struct *work_s) -{ - struct adis16209_state *st - =3D container_of(work_s, struct adis16209_state, - work_trigger_to_ring); - - int i =3D 0; - s16 *data; - size_t datasize =3D st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); - - data =3D kmalloc(datasize , GFP_KERNEL); - if (data =3D=3D NULL) { - dev_err(&st->us->dev, "memory alloc failed in ring bh"); - return; - } - - if (st->indio_dev->scan_count) - if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >=3D 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] =3D combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } - - /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) - *((s64 *)(data + ((i + 3)/4)*4)) =3D st->last_timestamp; - - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); - - iio_trigger_notify_done(st->indio_dev->trig); - kfree(data); - - return; -} - -/* in these circumstances is it better to go with unaligned packing and - * deal with the cost?*/ -static int adis16209_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) - /* Timestamp (aligned to s64) and data */ - size =3D (((indio_dev->scan_count * sizeof(s16)) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size =3D sizeof(s64); - else /* Data only */ - size =3D indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16209_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16209_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -void adis16209_unconfigure_ring(struct iio_dev *indio_dev) -{ - kfree(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->ring); -} - -int adis16209_configure_ring(struct iio_dev *indio_dev) -{ - int ret =3D 0; - struct adis16209_state *st =3D indio_dev->dev_data; - struct iio_ring_buffer *ring; - INIT_WORK(&st->work_trigger_to_ring, adis16209_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_rot.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_y.number); - indio_dev->scan_timestamp =3D true; - - indio_dev->scan_el_attrs =3D &adis16209_scan_el_group; - - ring =3D iio_sw_rb_allocate(indio_dev); - if (!ring) { - ret =3D -ENOMEM; - return ret; - } - indio_dev->ring =3D ring; - /* Effectively select the ring buffer implementation */ - iio_ring_sw_register_funcs(&ring->access); - ring->preenable =3D &adis16209_data_rdy_ring_preenable; - ring->postenable =3D &adis16209_data_rdy_ring_postenable; - ring->predisable =3D &adis16209_data_rdy_ring_predisable; - ring->owner =3D THIS_MODULE; - - indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL)= ; - if (indio_dev->pollfunc =3D=3D NULL) { - ret =3D -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main =3D &adis16209_poll_func_th; - indio_dev->pollfunc->private_data =3D indio_dev; - indio_dev->modes |=3D INDIO_RING_TRIGGERED; - return 0; - -error_iio_sw_rb_free: - iio_sw_rb_free(indio_dev->ring); - return ret; -} - -int adis16209_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16209_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} Index: drivers/staging/iio/accel/adis16209_trigger.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/accel/adis16209_trigger.c (revision 8893) +++ drivers/staging/iio/accel/adis16209_trigger.c (working copy) @@ -1,124 +0,0 @@ -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/sysfs.h> -#include <linux/list.h> -#include <linux/spi/spi.h> - -#include "../iio.h" -#include "../sysfs.h" -#include "../trigger.h" -#include "adis16209.h" - -/** - * adis16209_data_rdy_trig_poll() the event handler for the data rdy trig - **/ -static int adis16209_data_rdy_trig_poll(struct iio_dev *dev_info, - int index, - s64 timestamp, - int no_test) -{ - struct adis16209_state *st =3D iio_dev_get_devdata(dev_info); - struct iio_trigger *trig =3D st->trig; - - trig->timestamp =3D timestamp; - iio_trigger_poll(trig); - - return IRQ_HANDLED; -} - -IIO_EVENT_SH(data_rdy_trig, &adis16209_data_rdy_trig_poll); - -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); - -static struct attribute *adis16209_trigger_attrs[] =3D { - &dev_attr_name.attr, - NULL, -}; - -static const struct attribute_group adis16209_trigger_attr_group =3D { - .attrs =3D adis16209_trigger_attrs, -}; - -/** - * adis16209_data_rdy_trigger_set_state() set datardy interrupt state - **/ -static int adis16209_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - struct adis16209_state *st =3D trig->private_data; - struct iio_dev *indio_dev =3D st->indio_dev; - int ret =3D 0; - - dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); - ret =3D adis16209_set_irq(&st->indio_dev->dev, state); - if (state =3D=3D false) { - iio_remove_event_from_list(&iio_event_data_rdy_trig, - &indio_dev->interrupts[0] - ->ev_list); - flush_scheduled_work(); - } else { - iio_add_event_to_list(&iio_event_data_rdy_trig, - &indio_dev->interrupts[0]->ev_list); - } - return ret; -} - -/** - * adis16209_trig_try_reen() try renabling irq for data rdy trigger - * @trig: the datardy trigger - **/ -static int adis16209_trig_try_reen(struct iio_trigger *trig) -{ - struct adis16209_state *st =3D trig->private_data; - enable_irq(st->us->irq); - return 0; -} - -int adis16209_probe_trigger(struct iio_dev *indio_dev) -{ - int ret; - struct adis16209_state *st =3D indio_dev->dev_data; - - st->trig =3D iio_allocate_trigger(); - st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); - if (!st->trig->name) { - ret =3D -ENOMEM; - goto error_free_trig; - } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16209-dev%d", indio_dev->id); - st->trig->dev.parent =3D &st->us->dev; - st->trig->owner =3D THIS_MODULE; - st->trig->private_data =3D st; - st->trig->set_trigger_state =3D &adis16209_data_rdy_trigger_set_state; - st->trig->try_reenable =3D &adis16209_trig_try_reen; - st->trig->control_attrs =3D &adis16209_trigger_attr_group; - ret =3D iio_trigger_register(st->trig); - - /* select default trigger */ - indio_dev->trig =3D st->trig; - if (ret) - goto error_free_trig_name; - - return 0; - -error_free_trig_name: - kfree(st->trig->name); -error_free_trig: - iio_free_trigger(st->trig); - - return ret; -} - -void adis16209_remove_trigger(struct iio_dev *indio_dev) -{ - struct adis16209_state *state =3D indio_dev->dev_data; - - iio_trigger_unregister(state->trig); - kfree(state->trig->name); - iio_free_trigger(state->trig); -} Index: drivers/staging/iio/accel/adis16209.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/accel/adis16209.h (revision 8893) +++ drivers/staging/iio/accel/adis16209.h (working copy) @@ -101,33 +101,6 @@ #define ADIS16209_ERROR_ACTIVE (1<<14) -/** - * struct adis16209_state - device instance specific data - * @us: actual spi_device - * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN - * @inter: used to check if new interrupt has been triggered - * @last_timestamp: passing timestamp from th to bh of interrupt handler - * @indio_dev: industrial I/O device structure - * @trig: data ready trigger registered with iio - * @tx: transmit buffer - * @rx: recieve buffer - * @buf_lock: mutex to protect tx and rx - **/ -struct adis16209_state { - struct spi_device *us; - struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; - s64 last_timestamp; - struct iio_dev *indio_dev; - struct iio_trigger *trig; - u8 *tx; - u8 *rx; - struct mutex buf_lock; -}; - -int adis16209_set_irq(struct device *dev, bool enable); - #ifdef CONFIG_IIO_RING_BUFFER enum adis16209_scan { ADIS16209_SCAN_SUPPLY, @@ -139,55 +112,5 @@ ADIS16209_SCAN_INCLI_Y, ADIS16209_SCAN_ROT, }; - -void adis16209_remove_trigger(struct iio_dev *indio_dev); -int adis16209_probe_trigger(struct iio_dev *indio_dev); - -ssize_t adis16209_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf); - -int adis16209_configure_ring(struct iio_dev *indio_dev); -void adis16209_unconfigure_ring(struct iio_dev *indio_dev); - -int adis16209_initialize_ring(struct iio_ring_buffer *ring); -void adis16209_uninitialize_ring(struct iio_ring_buffer *ring); -#else /* CONFIG_IIO_RING_BUFFER */ - -static inline void adis16209_remove_trigger(struct iio_dev *indio_dev) -{ -} - -static inline int adis16209_probe_trigger(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline ssize_t -adis16209_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return 0; -} - -static int adis16209_configure_ring(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void adis16209_unconfigure_ring(struct iio_dev *indio_dev) -{ -} - -static inline int adis16209_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16209_uninitialize_ring(struct iio_ring_buffer *rin= g) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16209_H_ */ Index: drivers/staging/iio/accel/adis16209_core.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/accel/adis16209_core.c (revision 8893) +++ drivers/staging/iio/accel/adis16209_core.c (working copy) @@ -22,6 +22,9 @@ #include "../sysfs.h" #include "accel.h" #include "inclinometer.h" +#include "../trigger.h" +#include "../ring_generic.h" +#include "../common-ring-trigger.h" #include "../gyro/gyro.h" #include "../adc/adc.h" @@ -43,13 +46,14 @@ { int ret; struct iio_dev *indio_dev =3D dev_get_drvdata(dev); - struct adis16209_state *st =3D iio_dev_get_devdata(indio_dev); + struct iio_state *st =3D iio_dev_get_devdata(indio_dev); + struct spi_device *spi =3D iio_state_get_privdata(st); mutex_lock(&st->buf_lock); st->tx[0] =3D ADIS16209_WRITE_REG(reg_address); st->tx[1] =3D val; - ret =3D spi_write(st->us, st->tx, 2); + ret =3D spi_write(spi, st->tx, 2); mutex_unlock(&st->buf_lock); return ret; @@ -69,7 +73,8 @@ int ret; struct spi_message msg; struct iio_dev *indio_dev =3D dev_get_drvdata(dev); - struct adis16209_state *st =3D iio_dev_get_devdata(indio_dev); + struct iio_state *st =3D iio_dev_get_devdata(indio_dev); + struct spi_device *spi =3D iio_state_get_privdata(st); struct spi_transfer xfers[] =3D { { .tx_buf =3D st->tx, @@ -95,7 +100,7 @@ spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); spi_message_add_tail(&xfers[1], &msg); - ret =3D spi_sync(st->us, &msg); + ret =3D spi_sync(spi, &msg); mutex_unlock(&st->buf_lock); return ret; @@ -114,7 +119,8 @@ { struct spi_message msg; struct iio_dev *indio_dev =3D dev_get_drvdata(dev); - struct adis16209_state *st =3D iio_dev_get_devdata(indio_dev); + struct iio_state *st =3D iio_dev_get_devdata(indio_dev); + struct spi_device *spi =3D iio_state_get_privdata(st); int ret; struct spi_transfer xfers[] =3D { { @@ -139,9 +145,9 @@ spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); spi_message_add_tail(&xfers[1], &msg); - ret =3D spi_sync(st->us, &msg); + ret =3D spi_sync(spi, &msg); if (ret) { - dev_err(&st->us->dev, + dev_err(&spi->dev, "problem when reading 16 bit register 0x%02X", lower_reg_address); goto error_ret; @@ -285,12 +291,12 @@ return -EINVAL; } -int adis16209_set_irq(struct device *dev, bool enable) +static int adis16209_set_irq(struct iio_state *st, bool enable) { int ret =3D 0; u16 msc; - ret =3D adis16209_spi_read_reg_16(dev, ADIS16209_MSC_CTRL, &msc); + ret =3D adis16209_spi_read_reg_16(&st->indio_dev->dev, ADIS16209_MSC_CTRL, &msc); if (ret) goto error_ret; @@ -301,7 +307,7 @@ else msc &=3D ~ADIS16209_MSC_CTRL_DATA_RDY_EN; - ret =3D adis16209_spi_write_reg_16(dev, ADIS16209_MSC_CTRL, msc); + ret =3D adis16209_spi_write_reg_16(&st->indio_dev->dev, ADIS16209_MSC_CTRL, msc); error_ret: return ret; @@ -351,13 +357,55 @@ return ret; } -static int adis16209_initial_setup(struct adis16209_state *st) +/** + * adis16209_read_ring_data() read data registers which will be placed into ring + * @dev: device associated with child of actual device (iio_dev or iio_tri= g) + * @rx: somewhere to pass back the value read + **/ +static int adis16209_read_ring_data(struct iio_state *st, u8 *rx) { + struct spi_device *spi =3D iio_state_get_privdata(st); + struct spi_message msg; + struct spi_transfer xfers[ADIS16209_OUTPUTS + 1]; int ret; + int i; + + mutex_lock(&st->buf_lock); + + spi_message_init(&msg); + + memset(xfers, 0, sizeof(xfers)); + for (i =3D 0; i <=3D ADIS16209_OUTPUTS; i++) { + xfers[i].bits_per_word =3D 8; + xfers[i].cs_change =3D 1; + xfers[i].len =3D 2; + xfers[i].delay_usecs =3D 30; + xfers[i].tx_buf =3D st->tx + 2 * i; + st->tx[2 * i] + =3D ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i); + st->tx[2 * i + 1] =3D 0; + if (i >=3D 1) + xfers[i].rx_buf =3D rx + 2 * (i - 1); + spi_message_add_tail(&xfers[i], &msg); + } + + ret =3D spi_sync(spi, &msg); + if (ret) + dev_err(&spi->dev, "problem when burst reading"); + + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int adis16209_initial_setup(struct iio_state *st) +{ + int ret; + struct spi_device *spi =3D iio_state_get_privdata(st); struct device *dev =3D &st->indio_dev->dev; /* Disable IRQ */ - ret =3D adis16209_set_irq(dev, false); + ret =3D adis16209_set_irq(st, false); if (ret) { dev_err(dev, "disable irq failed"); goto err_ret; @@ -384,7 +432,7 @@ } printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n", - st->us->chip_select, st->us->irq); + spi->chip_select, spi->irq); err_ret: return ret; @@ -472,16 +520,54 @@ .attrs =3D adis16209_attributes, }; +static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14), + ADIS16209_SUPPLY_OUT, NULL); +static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14), + ADIS16209_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, IIO_SIGNED(14), + ADIS16209_YACCL_OUT, NULL); +static IIO_SCAN_EL_C(aux_adc, ADIS16209_SCAN_AUX_ADC, IIO_UNSIGNED(12), + ADIS16209_AUX_ADC, NULL); +static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, IIO_UNSIGNED(12), + ADIS16209_TEMP_OUT, NULL); +static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, IIO_SIGNED(14), + ADIS16209_XINCL_OUT, NULL); +static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, IIO_SIGNED(14), + ADIS16209_YINCL_OUT, NULL); +static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, IIO_SIGNED(14), + ADIS16209_ROT_OUT, NULL); + +static IIO_SCAN_EL_TIMESTAMP(8); + +static struct attribute *adis16209_scan_el_attrs[] =3D { + &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_accel_x.dev_attr.attr, + &iio_scan_el_accel_y.dev_attr.attr, + &iio_scan_el_aux_adc.dev_attr.attr, + &iio_scan_el_temp.dev_attr.attr, + &iio_scan_el_incli_x.dev_attr.attr, + &iio_scan_el_incli_y.dev_attr.attr, + &iio_scan_el_rot.dev_attr.attr, + &iio_scan_el_timestamp.dev_attr.attr, + NULL, +}; + +static struct attribute_group adis16209_scan_el_group =3D { + .attrs =3D adis16209_scan_el_attrs, + .name =3D "scan_elements", +}; + static int __devinit adis16209_probe(struct spi_device *spi) { int ret, regdone =3D 0; - struct adis16209_state *st =3D kzalloc(sizeof *st, GFP_KERNEL); + struct iio_state *st =3D kzalloc(sizeof *st, GFP_KERNEL); if (!st) { ret =3D -ENOMEM; goto error_ret; } /* this is only used for removal purposes */ spi_set_drvdata(spi, st); + iio_state_set_privdata(st, spi); /* Allocate the comms buffers */ st->rx =3D kzalloc(sizeof(*st->rx)*ADIS16209_MAX_RX, GFP_KERNEL); @@ -494,7 +580,12 @@ ret =3D -ENOMEM; goto error_free_rx; } - st->us =3D spi; + + st->irq =3D spi->irq; + st->set_irq =3D adis16209_set_irq; + st->hw_read_ring =3D adis16209_read_ring_data; + st->parent_dev =3D &spi->dev; + mutex_init(&st->buf_lock); /* setup the industrialio driver allocated elements */ st->indio_dev =3D iio_allocate_device(); @@ -511,7 +602,18 @@ st->indio_dev->driver_module =3D THIS_MODULE; st->indio_dev->modes =3D INDIO_DIRECT_MODE; - ret =3D adis16209_configure_ring(st->indio_dev); + iio_scan_mask_set(st->indio_dev, iio_scan_el_supply.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_rot.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_accel_x.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_accel_y.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_temp.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_aux_adc.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_incli_x.number); + iio_scan_mask_set(st->indio_dev, iio_scan_el_incli_y.number); + st->indio_dev->scan_timestamp =3D true; + st->indio_dev->scan_el_attrs =3D &adis16209_scan_el_group; + + ret =3D iio_configure_common_ring(st->indio_dev); if (ret) goto error_free_dev; @@ -520,7 +622,7 @@ goto error_unreg_ring_funcs; regdone =3D 1; - ret =3D adis16209_initialize_ring(st->indio_dev->ring); + ret =3D iio_initialize_common_ring(st->indio_dev->ring); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; @@ -533,9 +635,9 @@ IRQF_TRIGGER_RISING, "adis16209"); if (ret) - goto error_uninitialize_ring; + goto error_uninitialize_common_ring; - ret =3D adis16209_probe_trigger(st->indio_dev); + ret =3D iio_probe_common_trigger(st->indio_dev); if (ret) goto error_unregister_line; } @@ -543,18 +645,18 @@ /* Get the device into a sane initial state */ ret =3D adis16209_initial_setup(st); if (ret) - goto error_remove_trigger; + goto error_remove_common_trigger; return 0; -error_remove_trigger: - adis16209_remove_trigger(st->indio_dev); +error_remove_common_trigger: + iio_remove_common_trigger(st->indio_dev); error_unregister_line: if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); -error_uninitialize_ring: - adis16209_uninitialize_ring(st->indio_dev->ring); +error_uninitialize_common_ring: + iio_uninitialize_common_ring(st->indio_dev->ring); error_unreg_ring_funcs: - adis16209_unconfigure_ring(st->indio_dev); + iio_unconfigure_common_ring(st->indio_dev); error_free_dev: if (regdone) iio_device_unregister(st->indio_dev); @@ -572,18 +674,18 @@ static int adis16209_remove(struct spi_device *spi) { - struct adis16209_state *st =3D spi_get_drvdata(spi); + struct iio_state *st =3D spi_get_drvdata(spi); struct iio_dev *indio_dev =3D st->indio_dev; flush_scheduled_work(); - adis16209_remove_trigger(indio_dev); + iio_remove_common_trigger(indio_dev); if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16209_uninitialize_ring(indio_dev->ring); + iio_uninitialize_common_ring(indio_dev->ring); iio_device_unregister(indio_dev); - adis16209_unconfigure_ring(indio_dev); + iio_unconfigure_common_ring(indio_dev); kfree(st->tx); kfree(st->rx); kfree(st); Index: drivers/staging/iio/accel/Makefile =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/accel/Makefile (revision 8893) +++ drivers/staging/iio/accel/Makefile (working copy) @@ -15,7 +15,6 @@ obj-$(CONFIG_ADIS16204) +=3D adis16204.o adis16209-y :=3D adis16209_core.o -adis16209-$(CONFIG_IIO_RING_BUFFER) +=3D adis16209_ring.o adis16209_trigge= r.o obj-$(CONFIG_ADIS16209) +=3D adis16209.o adis16220-y :=3D adis16220_core.o On Thu, Jun 10, 2010 at 12:48 PM, Barry Song <21cnbao@gmail.com> wrote: > Just RFC for discussion. It is not the last patch To keep the change > lest, i extract the common factor for most iio devices to a common > ring trigger module. Most devices can use the interfaces in this > module directly. So copy-paste for ring and trigger is not necessary > now. > > For iio core changes: > 1. extract xxx_state to iio_state and add a private data to contain > chip-specific data > 2. extract all xxx_ring/xxx_trigger api to common api > > Index: drivers/staging/iio/iio.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- drivers/staging/iio/iio.h =C2=A0 (revision 8893) > +++ drivers/staging/iio/iio.h =C2=A0 (working copy) > @@ -447,4 +447,46 @@ > > =C2=A0int iio_get_new_idr_val(struct idr *this_idr); > =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); > + > +/** > + * struct iio_state - hardware level hooks for iio device > + * @work_trigger_to_ring: bh for triggered event handling > + * @work_cont_thresh: CLEAN > + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if ne= w interrupt has been triggered > + * @last_timestamp: =C2=A0 =C2=A0passing timestamp from th to bh of inte= rrupt handler > + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 industrial I/O device structu= re > + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready tri= gger registered with iio > + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0transmit buffer > + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0recieve buffer > + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mutex to protect tx and = rx > + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0interrup= t number > + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the disabl= e/enable of external interrupt > + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware by s= pi/i2c. > + **/ > +struct iio_state { > + =C2=A0 =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 *parent_dev; > + =C2=A0 =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0work_trigger_to_ring; > + =C2=A0 =C2=A0 =C2=A0 struct iio_work_cont =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_cont_thresh; > + =C2=A0 =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; > + =C2=A0 =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0*indio_dev; > + =C2=A0 =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0*trig; > + =C2=A0 =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; > + =C2=A0 =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; > + =C2=A0 =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; > + =C2=A0 =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; > + =C2=A0 =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); > + =C2=A0 =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); > + =C2=A0 =C2=A0 =C2=A0 void *priv; > +}; > + > +static inline void iio_state_set_privdata(struct iio_state *st, void *da= ta) > +{ > + =C2=A0 =C2=A0 =C2=A0 st->priv =3D data; > +} > + > +static inline void * iio_state_get_privdata(struct iio_state *st) > +{ > + =C2=A0 =C2=A0 =C2=A0 return st->priv; > +} > + > =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ > Index: drivers/staging/iio/common-ring-trigger.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- drivers/staging/iio/common-ring-trigger.c =C2=A0 (revision 0) > +++ drivers/staging/iio/common-ring-trigger.c =C2=A0 (revision 0) > @@ -0,0 +1,277 @@ > +/* The software ring with trigger which can be used by most drivers > + * > + * Copyright (c) 2010 Barry Song > + * > + * This program is free software; you can redistribute it and/or modify = it > + * under the terms of the GNU General Public License version 2 as publis= hed by > + * the Free Software Foundation. > + * > + */ > +#include <linux/kernel.h> > +#include <linux/device.h> > +#include <linux/interrupt.h> > +#include <linux/fs.h> > +#include <linux/poll.h> > +#include <linux/module.h> > +#include <linux/cdev.h> > +#include <linux/slab.h> > + > +#include "iio.h" > +#include "ring_generic.h" > +#include "trigger.h" > +#include "ring_sw.h" > + > +/* > + * combine_8_to_16(): utility function to munge to u8s into u16 > + */ > +static inline u16 combine_8_to_16(u8 lower, u8 upper) > +{ > + =C2=A0 =C2=A0 =C2=A0 u16 _lower =3D lower; > + =C2=A0 =C2=A0 =C2=A0 u16 _upper =3D upper; > + =C2=A0 =C2=A0 =C2=A0 return _lower | (_upper << 8); > +} > + > +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio= _dev); > + =C2=A0 =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; > + =C2=A0 =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); > +} > + > +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_= s, struct iio_state, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); > + > + =C2=A0 =C2=A0 =C2=A0 int i =3D 0; > + =C2=A0 =C2=A0 =C2=A0 s16 *data; > + =C2=A0 =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd= (st->indio_dev->ring); > + > + =C2=A0 =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->pare= nt_dev, "memory alloc failed in ring bh"); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 if (st->indio_dev->scan_count) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(s= t, st->rx) >=3D 0) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 for (; i < st->indio_dev->scan_count; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1= ], > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 st->rx[i*2]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 } > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte boun= dary */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(data += ((i + 3)/4)*4)) =3D st->last_timestamp; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->ind= io_dev->ring, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(u8 *)data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0st->last_timestamp); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->trig)= ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > +} > + > +static int iio_common_ring_preenable(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 size_t size; > + =C2=A0 =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); > + =C2=A0 =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, i= f not fail*/ > + =C2=A0 =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_tim= estamp)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; > + > + =C2=A0 =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_ti= mestamp) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 if (indio_dev->scan_count) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data *= / > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * size= of(s16)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 & ~(sizeof(s64) - 1)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64= ); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 else /* Timestamp only =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 size =3D indio_dev->scan_count*sizeof(s16); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->acces= s.set_bpd(indio_dev->ring, size); > + =C2=A0 =C2=A0 =C2=A0 } > + > + =C2=A0 =C2=A0 =C2=A0 return 0; > +} > + > +static int iio_common_ring_postenable(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_at= tach_poll_func(indio_dev->trig, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 indio_dev->pollfunc) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; > +} > + > +static int iio_common_ring_predisable(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_de= ttach_poll_func(indio_dev->trig, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; > +} > + > +int iio_configure_common_ring(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 int ret =3D 0; > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; > + =C2=A0 =C2=A0 =C2=A0 struct iio_ring_buffer *ring; > + =C2=A0 =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_tr= igger_bh_to_ring); > + > + =C2=A0 =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); > + =C2=A0 =C2=A0 =C2=A0 if (!ring) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; > + =C2=A0 =C2=A0 =C2=A0 } > + =C2=A0 =C2=A0 =C2=A0 indio_dev->ring =3D ring; > + > + =C2=A0 =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); > + =C2=A0 =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; > + =C2=A0 =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; > + =C2=A0 =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; > + =C2=A0 =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; > + > + =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev-= >pollfunc), GFP_KERNEL); > + =C2=A0 =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_f= ree;; > + =C2=A0 =C2=A0 =C2=A0 } > + =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_commo= n_ring_poll_func_th; > + =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; > + =C2=A0 =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; > + =C2=A0 =C2=A0 =C2=A0 return 0; > + > +error_iio_sw_rb_free: > + =C2=A0 =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); > + =C2=A0 =C2=A0 =C2=A0 return ret; > +} > +EXPORT_SYMBOL(iio_configure_common_ring); > + > +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); > + =C2=A0 =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); > +} > +EXPORT_SYMBOL(iio_unconfigure_common_ring); > + > +int iio_initialize_common_ring(struct iio_ring_buffer *ring) > +{ > + =C2=A0 =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); > +} > +EXPORT_SYMBOL(iio_initialize_common_ring); > + > +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) > +{ > + =C2=A0 =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); > +} > +EXPORT_SYMBOL(iio_uninitialize_common_ring); > + > +static int iio_common_trigger_poll(struct iio_dev *dev_info, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_i= nfo); > + =C2=A0 =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; > + > + =C2=A0 =C2=A0 =C2=A0 trig->timestamp =3D timestamp; > + =C2=A0 =C2=A0 =C2=A0 iio_trigger_poll(trig); > + > + =C2=A0 =C2=A0 =C2=A0 return IRQ_HANDLED; > +} > + > +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); > + > +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); > + > +static struct attribute *iio_trigger_attrs[] =3D { > + =C2=A0 =C2=A0 =C2=A0 &dev_attr_name.attr, > + =C2=A0 =C2=A0 =C2=A0 NULL, > +}; > + > +static const struct attribute_group iio_trigger_attr_group =3D { > + =C2=A0 =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, > +}; > + > +static int iio_common_trigger_try_reen(struct iio_trigger *trig) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; > + =C2=A0 =C2=A0 =C2=A0 enable_irq(st->irq); > + =C2=A0 =C2=A0 =C2=A0 return 0; > +} > + > +static int iio_common_trigger_set_state(struct iio_trigger *trig, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; > + =C2=A0 =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; > + =C2=A0 =C2=A0 =C2=A0 int ret =3D 0; > + > + =C2=A0 =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, st= ate); > + =C2=A0 =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); > + =C2=A0 =C2=A0 =C2=A0 if (state =3D=3D false) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_= list(&iio_event_common_trig, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work()= ; > + =C2=A0 =C2=A0 =C2=A0 } else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(= &iio_event_common_trig, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); > + =C2=A0 =C2=A0 =C2=A0 } > + =C2=A0 =C2=A0 =C2=A0 return ret; > +} > + > +int iio_probe_common_trigger(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 int ret; > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; > + > + =C2=A0 =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); > + =C2=A0 =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH= , GFP_KERNEL); > + =C2=A0 =C2=A0 =C2=A0 if (!st->trig->name) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; > + =C2=A0 =C2=A0 =C2=A0 } > + =C2=A0 =C2=A0 =C2=A0 snprintf((char *)st->trig->name, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 IIO_TRIGGER_NAME_LENGTH, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 "iio-dev%d", indio_dev->id); > + =C2=A0 =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; > + =C2=A0 =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; > + =C2=A0 =C2=A0 =C2=A0 st->trig->private_data =3D st; > + =C2=A0 =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigge= r_set_state; > + =C2=A0 =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try= _reen; > + =C2=A0 =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_grou= p; > + =C2=A0 =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); > + > + =C2=A0 =C2=A0 =C2=A0 /* select default trigger */ > + =C2=A0 =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; > + =C2=A0 =C2=A0 =C2=A0 if (ret) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_n= ame; > + > + =C2=A0 =C2=A0 =C2=A0 return 0; > + > +error_free_trig_name: > + =C2=A0 =C2=A0 =C2=A0 kfree(st->trig->name); > +error_free_trig: > + =C2=A0 =C2=A0 =C2=A0 iio_free_trigger(st->trig); > + > + =C2=A0 =C2=A0 =C2=A0 return ret; > +} > +EXPORT_SYMBOL(iio_probe_common_trigger); > + > +void iio_remove_common_trigger(struct iio_dev *indio_dev) > +{ > + =C2=A0 =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; > + > + =C2=A0 =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); > + =C2=A0 =C2=A0 =C2=A0 kfree(state->trig->name); > + =C2=A0 =C2=A0 =C2=A0 iio_free_trigger(state->trig); > +} > +EXPORT_SYMBOL(iio_remove_common_trigger); > Index: drivers/staging/iio/common-ring-trigger.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- drivers/staging/iio/common-ring-trigger.h =C2=A0 (revision 0) > +++ drivers/staging/iio/common-ring-trigger.h =C2=A0 (revision 0) > @@ -0,0 +1,24 @@ > +/* The industrial I/O frequently used ring with trigger > + * > + * Copyright (c) 2010 Barry Song > + * > + * This program is free software; you can redistribute it and/or modify = it > + * under the terms of the GNU General Public License version 2 as publis= hed by > + * the Free Software Foundation. > + * > + */ > + > +#ifndef _IIO_COMMON_RING_TRIGGER_H_ > +#define _IIO_COMMON_RING_TRIGGER_H_ > + > +#include "iio.h" > +#include "ring_generic.h" > + > +int iio_configure_common_ring(struct iio_dev *indio_dev); > +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); > +int iio_initialize_common_ring(struct iio_ring_buffer *ring); > +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); > + > +int iio_probe_common_trigger(struct iio_dev *indio_dev); > +void iio_remove_common_trigger(struct iio_dev *indio_dev); > +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ > Index: drivers/staging/iio/Kconfig > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- drivers/staging/iio/Kconfig (revision 8893) > +++ drivers/staging/iio/Kconfig (working copy) > @@ -38,6 +38,12 @@ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring buffers. =C2=A0The triggers are ef= fectively a 'capture > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data now' interrupt. > > +config IIO_COMMON_RING_TRIGGER > + =C2=A0 =C2=A0 =C2=A0 boolean "Enable frequently used ring with trigger" > + =C2=A0 =C2=A0 =C2=A0 depends on IIO_SW_RING && IIO_TRIGGER > + =C2=A0 =C2=A0 =C2=A0 help > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 Provides a generic ring with trigger. I can= be used by most > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 IIO devices. > > =C2=A0source "drivers/staging/iio/accel/Kconfig" > =C2=A0source "drivers/staging/iio/adc/Kconfig" > Index: drivers/staging/iio/Makefile > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0 =C2=A0(revision 889= 3) > +++ drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0 =C2=A0(working copy= ) > @@ -9,6 +9,8 @@ > > =C2=A0obj-$(CONFIG_IIO_SW_RING) +=3D ring_sw.o > > +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) +=3D common-ring-trigger.o > + > =C2=A0obj-y +=3D accel/ > =C2=A0obj-y +=3D adc/ > =C2=A0obj-y +=3D addac/ > > > > On Wed, Jun 2, 2010 at 9:21 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> On 06/02/10 09:01, Barry Song wrote: >>> On Mon, Feb 22, 2010 at 7:16 PM, Jonathan Cameron <jic23@cam.ac.uk> wro= te: >>>> Hi All, >>>> >>>> Just for reference as I'll be doing a proper announcement later. >>>> We now have linux-iio@vger.kernel.org as a mailing list for the projec= t. >>>> Unless others have tracked it down it currently only has me as a membe= r >>>> though and I'm waiting for confirmation from marc.info of an archive. >>>> >>>>> Hi Jonathan, >>>>> Now users depend on iio ring events(IIO_EVENT_CODE_RING_50/75/100_FUL= L) >>>>> to read data: >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D= fread(&dat, 1, sizeof(struct >>>>> iio_event_data), >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fp_ev); >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (dat.i= d) { >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVEN= T_CODE_RING_100_FULL: >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 toread =3D RingLength; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 break; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVEN= T_CODE_RING_75_FULL: >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 toread =3D RingLength*3/4; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 break; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case IIO_EVEN= T_CODE_RING_50_FULL: >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 toread =3D RingLength/2; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 break; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 default: >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 printf("Unexpecteded event code\n"); >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 continue; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 read_size =3D= read(fp, >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data, >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0toread*size_from_scanmode(= NumVals, >>>>> scan_ts)); >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (read_size= =3D=3D -EAGAIN) { >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 printf("nothing available \n"); >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 continue; >>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } >>>>> And iio ring access node doesn't support blocking io too. =C2=A0It se= ems we >>>>> lost to let users read data once ring is not empty. And some users ma= ybe >>>>> not care about iio ring events at all, but just want to read data lik= e a >>>>> input or audio driver. So how about adding the following support in i= io >>>>> ring: >>>>> 1. add NOT EMPTY event in IIO event nodes >>>> Not keen. =C2=A0It might lead to a storm of events (at least it might = in a >>>> cleverer ring buffer implementation or during a blocking read). =C2=A0= Actually >>>> in this particular case it probably wouldn't do any harm. >>>>> 2. add blocking io support in read function of IIO access nodes >>>> That I agree would be a good idea. =C2=A0If we support poll/select on = the buffer access >>>> chrdev then we will get the same effect per having a not empty event a= nd cleaner >>>> semantics for anyone not interested in the other events. Not to mentio= n I expect >>>> we will soon have alternative ring buffer implementations that don't s= upply any >>>> events at all and hence don't event have the relevant chrdev. >>>> >>>> As things are, you can quite happily read whenever you like. =C2=A0Now= you mention it, >>>> that example code is somewhat missleading! The issue with >>>> this ring buffer implementation is the handling of a true blocking rea= d is complex >>>> as at any given time you aren't guaranteed to get what you asked for e= ven if it was >>>> there when you started the read. It should be possible to work around = that though. >>>> >>>> It's possible this functionality might be better added to an alternati= ve ring buffer >>>> implementation. Be vary wary of that ring implementation in general! I= am and I wrote it. >>>>> If you agree with that, I can begin to add these and send you a patch= . >>>>> And a problem I don't know is what you and other people have changed = to >>>>> Greg's staging tree, and I am not sure what tree the patch should be >>>>> againest. >>>> Nothing has changed in this region of the code. =C2=A0In fact I think = all that >>>> has gone into Greg's tree is a clean up patch form Mark Brown making a= few >>>> functions static. Right now I'm still getting the max1363 driver into >>>> a state where it will be possible to do the ABI changes. >>>>> >>>>> For long term plan, is it possible for ring common level to handle mo= re >>>>> common work to avoid code repeating in different drivers? >>>> I'm certainly happy for that to be the case if it becomes apparent whi= ch functionality >>>> is shared. =C2=A0I haven't seen any substantial cases as yet, but then= I may well be missing >>>> things so feel free to submit suggestions (or as ever the better optio= n of patches). >>> >>> Now we have many drivers using SW ring with same >>> preenable(),postenable(),predisable(), >>> initialize_ring(),uninitialize_ring(),poll_func(),probe_trigger(), >>> remove_trigger(). Can we move them to IIO common layer as a base class >>> methods. And the derived class can overload them if they have special >>> implement? Most devices just use the common layer and don't need to >>> copy codes. >> Sounds sensible. Please propose a patch. >> >> Jonathan >> > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-10 4:48 ` Barry Song 2010-06-10 4:51 ` Barry Song @ 2010-06-10 13:48 ` Jonathan Cameron 2010-06-11 3:19 ` Barry Song 2010-06-25 17:18 ` Jonathan Cameron 2 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-06-10 13:48 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/10/10 05:48, Barry Song wrote: > Just RFC for discussion. It is not the last patch To keep the change > lest, i extract the common factor for most iio devices to a common > ring trigger module. Most devices can use the interfaces in this > module directly. So copy-paste for ring and trigger is not necessary > now. Hi Barry, I'm afraid I'm not in a position to take a particularly close look at this right now (on a rather slow net connection) Thanks for taking a look at what we can unify. My immediate thought is that this patch may go a little too far, certainly at this stage. It produces generic support for a particular type of trigger (fine and useful) but I'm not sure this should be grouped with the ring buffer setup elements. There are plenty of devices that would benefit from parts of this code, but currently it is all of the take it or leave it variety. In particular I'm not sure the ring buffer filling code should be in here. It really isn't as consistent as the code implies and by the presense of that element you have reduces the general usefulness of rest. I'm very doubtful that we want to move things like the rx and tx buffers out of the device drivers themselves. The device drivers should control all access to the device, not a core driver like this. Currently we don't have internal hooks to the contents of the 'scans '. These could be added, but I think that would add more complexity than simply allowing the drivers to handle this aspect, not to mention adding some unecessary time penalty to this path. > > For iio core changes: > 1. extract xxx_state to iio_state and add a private data to contain > chip-specific data > 2. extract all xxx_ring/xxx_trigger api to common api > > Index: drivers/staging/iio/iio.h > =================================================================== > --- drivers/staging/iio/iio.h (revision 8893) > +++ drivers/staging/iio/iio.h (working copy) > @@ -447,4 +447,46 @@ > > int iio_get_new_idr_val(struct idr *this_idr); > void iio_free_idr_val(struct idr *this_idr, int id); > + > +/** > + * struct iio_state - hardware level hooks for iio device > + * @work_trigger_to_ring: bh for triggered event handling > + * @work_cont_thresh: CLEAN > + * @inter: used to check if new interrupt has been triggered > + * @last_timestamp: passing timestamp from th to bh of interrupt handler > + * @indio_dev: industrial I/O device structure > + * @trig: data ready trigger registered with iio > + * @tx: transmit buffer > + * @rx: recieve buffer > + * @buf_lock: mutex to protect tx and rx > + * @irq: interrupt number > + * @set_irq: control the disable/enable of external interrupt > + * @hw_read_ring: read ring data from hardware by spi/i2c. > + **/ > +struct iio_state { > + struct device *parent_dev; > + struct work_struct work_trigger_to_ring; > + struct iio_work_cont work_cont_thresh; > + s64 last_timestamp; > + struct iio_dev *indio_dev; > + struct iio_trigger *trig; > + u8 *tx; > + u8 *rx; > + struct mutex buf_lock; > + int irq; > + int (*set_irq)(struct iio_state *st, bool enable); > + int (*hw_read_ring)(struct iio_state *st, u8 *rx); > + void *priv; > +}; > + > +static inline void iio_state_set_privdata(struct iio_state *st, void *data) > +{ > + st->priv = data; > +} > + > +static inline void * iio_state_get_privdata(struct iio_state *st) > +{ > + return st->priv; > +} > + > #endif /* _INDUSTRIAL_IO_H_ */ > Index: drivers/staging/iio/common-ring-trigger.c > =================================================================== > --- drivers/staging/iio/common-ring-trigger.c (revision 0) > +++ drivers/staging/iio/common-ring-trigger.c (revision 0) > @@ -0,0 +1,277 @@ > +/* The software ring with trigger which can be used by most drivers > + * > + * Copyright (c) 2010 Barry Song > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + */ > +#include <linux/kernel.h> > +#include <linux/device.h> > +#include <linux/interrupt.h> > +#include <linux/fs.h> > +#include <linux/poll.h> > +#include <linux/module.h> > +#include <linux/cdev.h> > +#include <linux/slab.h> > + > +#include "iio.h" > +#include "ring_generic.h" > +#include "trigger.h" > +#include "ring_sw.h" > + > +/* > + * combine_8_to_16(): utility function to munge to u8s into u16 > + */ > +static inline u16 combine_8_to_16(u8 lower, u8 upper) > +{ > + u16 _lower = lower; > + u16 _upper = upper; > + return _lower | (_upper << 8); > +} > + > +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) > +{ > + struct iio_state *st = iio_dev_get_devdata(indio_dev); > + st->last_timestamp = indio_dev->trig->timestamp; > + schedule_work(&st->work_trigger_to_ring); > +} > +/ This function is the one that mainly bothers me. We might have a number of devices that do fit in here but there are others that would use pretty much everything else but this. I'd possibly be more inclined to leave this to the drivers. That is where the knowledge about the data layout in 'rx' comes from. > +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) > +{ > + struct iio_state *st > + = container_of(work_s, struct iio_state, > + work_trigger_to_ring); > + > + int i = 0; > + s16 *data; > + size_t datasize = st->indio_dev > + ->ring->access.get_bpd(st->indio_dev->ring); > + > + data = kmalloc(datasize , GFP_KERNEL); > + if (data == NULL) { > + dev_err(st->parent_dev, "memory alloc failed in ring bh"); > + return; > + } > + > + if (st->indio_dev->scan_count) > + if (st->hw_read_ring(st, st->rx) >= 0) > + for (; i < st->indio_dev->scan_count; i++) { > + data[i] = combine_8_to_16(st->rx[i*2+1], > + st->rx[i*2]); > + } > + > + /* Guaranteed to be aligned with 8 byte boundary */ > + if (st->indio_dev->scan_timestamp) > + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; > + > + st->indio_dev->ring->access.store_to(st->indio_dev->ring, > + (u8 *)data, > + st->last_timestamp); > + > + iio_trigger_notify_done(st->indio_dev->trig); > + kfree(data); > + > + return; > +} > + > +static int iio_common_ring_preenable(struct iio_dev *indio_dev) > +{ > + size_t size; > + dev_dbg(&indio_dev->dev, "%s\n", __func__); > + /* Check if there are any scan elements enabled, if not fail*/ > + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) > + return -EINVAL; > + > + if (indio_dev->ring->access.set_bpd) { > + if (indio_dev->scan_timestamp) > + if (indio_dev->scan_count) > + /* Timestamp (aligned to s64) and data */ > + size = (((indio_dev->scan_count * sizeof(s16)) > + + sizeof(s64) - 1) > + & ~(sizeof(s64) - 1)) > + + sizeof(s64); > + else /* Timestamp only */ > + size = sizeof(s64); > + else /* Data only */ > + size = indio_dev->scan_count*sizeof(s16); > + indio_dev->ring->access.set_bpd(indio_dev->ring, size); > + } > + > + return 0; > +} > + > +static int iio_common_ring_postenable(struct iio_dev *indio_dev) > +{ > + return indio_dev->trig > + ? iio_trigger_attach_poll_func(indio_dev->trig, > + indio_dev->pollfunc) > + : 0; > +} > + > +static int iio_common_ring_predisable(struct iio_dev *indio_dev) > +{ > + return indio_dev->trig > + ? iio_trigger_dettach_poll_func(indio_dev->trig, > + indio_dev->pollfunc) > + : 0; > +} > + > +int iio_configure_common_ring(struct iio_dev *indio_dev) > +{ > + int ret = 0; > + struct iio_state *st = indio_dev->dev_data; > + struct iio_ring_buffer *ring; > + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); > + > + ring = iio_sw_rb_allocate(indio_dev); > + if (!ring) { > + ret = -ENOMEM; > + return ret; > + } > + indio_dev->ring = ring; > + > + iio_ring_sw_register_funcs(&ring->access); > + ring->preenable = &iio_common_ring_preenable; > + ring->postenable = &iio_common_ring_postenable; > + ring->predisable = &iio_common_ring_predisable; > + ring->owner = THIS_MODULE; > + > + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); > + if (indio_dev->pollfunc == NULL) { > + ret = -ENOMEM; > + goto error_iio_sw_rb_free;; > + } > + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; > + indio_dev->pollfunc->private_data = indio_dev; > + indio_dev->modes |= INDIO_RING_TRIGGERED; > + return 0; > + > +error_iio_sw_rb_free: > + iio_sw_rb_free(indio_dev->ring); > + return ret; > +} > +EXPORT_SYMBOL(iio_configure_common_ring); > + > +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) > +{ > + kfree(indio_dev->pollfunc); > + iio_sw_rb_free(indio_dev->ring); > +} > +EXPORT_SYMBOL(iio_unconfigure_common_ring); > + This next one is pointless except possibly to unify some naming so why do it? > +int iio_initialize_common_ring(struct iio_ring_buffer *ring) > +{ > + return iio_ring_buffer_register(ring, 0); > +} > +EXPORT_SYMBOL(iio_initialize_common_ring); > + > +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) > +{ > + iio_ring_buffer_unregister(ring); > +} > +EXPORT_SYMBOL(iio_uninitialize_common_ring); > + > +static int iio_common_trigger_poll(struct iio_dev *dev_info, > + int index, > + s64 timestamp, > + int no_test) > +{ > + struct iio_state *st = iio_dev_get_devdata(dev_info); > + struct iio_trigger *trig = st->trig; > + > + trig->timestamp = timestamp; > + iio_trigger_poll(trig); > + > + return IRQ_HANDLED; > +} > + > +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); > + > +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); > + > +static struct attribute *iio_trigger_attrs[] = { > + &dev_attr_name.attr, > + NULL, > +}; > + > +static const struct attribute_group iio_trigger_attr_group = { > + .attrs = iio_trigger_attrs, > +}; > + > +static int iio_common_trigger_try_reen(struct iio_trigger *trig) > +{ > + struct iio_state *st = trig->private_data; > + enable_irq(st->irq); > + return 0; > +} > + > +static int iio_common_trigger_set_state(struct iio_trigger *trig, > + bool state) > +{ > + struct iio_state *st = trig->private_data; > + struct iio_dev *indio_dev = st->indio_dev; > + int ret = 0; > + > + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); > + ret = st->set_irq(st, state); This again is making some nasty assumptions. Yes some drivers use a shared event to supply dat ready events, others do not and if the line isn't shared they shouldn't as it adds a fair bit of complexity to this fast path. > + if (state == false) { > + iio_remove_event_from_list(&iio_event_common_trig, > + &indio_dev->interrupts[0] > + ->ev_list); > + flush_scheduled_work(); > + } else { > + iio_add_event_to_list(&iio_event_common_trig, > + &indio_dev->interrupts[0]->ev_list); > + } > + return ret; > +} > + > +int iio_probe_common_trigger(struct iio_dev *indio_dev) > +{ > + int ret; > + struct iio_state *st = indio_dev->dev_data; > + > + st->trig = iio_allocate_trigger(); > + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); > + if (!st->trig->name) { > + ret = -ENOMEM; > + goto error_free_trig; > + } > + snprintf((char *)st->trig->name, > + IIO_TRIGGER_NAME_LENGTH, > + "iio-dev%d", indio_dev->id); > + st->trig->dev.parent = st->parent_dev; > + st->trig->owner = THIS_MODULE; > + st->trig->private_data = st; > + st->trig->set_trigger_state = &iio_common_trigger_set_state; > + st->trig->try_reenable = &iio_common_trigger_try_reen; > + st->trig->control_attrs = &iio_trigger_attr_group; > + ret = iio_trigger_register(st->trig); > + > + /* select default trigger */ > + indio_dev->trig = st->trig; > + if (ret) > + goto error_free_trig_name; > + > + return 0; > + > +error_free_trig_name: > + kfree(st->trig->name); > +error_free_trig: > + iio_free_trigger(st->trig); > + > + return ret; > +} > +EXPORT_SYMBOL(iio_probe_common_trigger); > + > +void iio_remove_common_trigger(struct iio_dev *indio_dev) > +{ > + struct iio_state *state = indio_dev->dev_data; > + > + iio_trigger_unregister(state->trig); > + kfree(state->trig->name); > + iio_free_trigger(state->trig); > +} > +EXPORT_SYMBOL(iio_remove_common_trigger); > Index: drivers/staging/iio/common-ring-trigger.h > =================================================================== > --- drivers/staging/iio/common-ring-trigger.h (revision 0) > +++ drivers/staging/iio/common-ring-trigger.h (revision 0) > @@ -0,0 +1,24 @@ > +/* The industrial I/O frequently used ring with trigger > + * > + * Copyright (c) 2010 Barry Song > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + */ > + > +#ifndef _IIO_COMMON_RING_TRIGGER_H_ > +#define _IIO_COMMON_RING_TRIGGER_H_ > + > +#include "iio.h" > +#include "ring_generic.h" > + > +int iio_configure_common_ring(struct iio_dev *indio_dev); > +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); > +int iio_initialize_common_ring(struct iio_ring_buffer *ring); > +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); > + > +int iio_probe_common_trigger(struct iio_dev *indio_dev); > +void iio_remove_common_trigger(struct iio_dev *indio_dev); > +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ > Index: drivers/staging/iio/Kconfig > =================================================================== > --- drivers/staging/iio/Kconfig (revision 8893) > +++ drivers/staging/iio/Kconfig (working copy) > @@ -38,6 +38,12 @@ > ring buffers. The triggers are effectively a 'capture > data now' interrupt. > > +config IIO_COMMON_RING_TRIGGER > + boolean "Enable frequently used ring with trigger" > + depends on IIO_SW_RING && IIO_TRIGGER > + help > + Provides a generic ring with trigger. I can be used by most > + IIO devices. > > source "drivers/staging/iio/accel/Kconfig" > source "drivers/staging/iio/adc/Kconfig" > Index: drivers/staging/iio/Makefile > =================================================================== > --- drivers/staging/iio/Makefile (revision 8893) > +++ drivers/staging/iio/Makefile (working copy) > @@ -9,6 +9,8 @@ > > obj-$(CONFIG_IIO_SW_RING) += ring_sw.o > > +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) += common-ring-trigger.o > + > obj-y += accel/ > obj-y += adc/ > obj-y += addac/ > > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-10 13:48 ` Jonathan Cameron @ 2010-06-11 3:19 ` Barry Song 2010-06-11 10:22 ` Jonathan Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-11 3:19 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 06/10/10 05:48, Barry Song wrote: >> Just RFC for discussion. It is not the last patch To keep the change >> lest, i extract the common factor for most iio devices to a common >> ring trigger module. Most devices can use the interfaces in this >> module directly. So copy-paste for ring and trigger is not necessary >> now. > Hi Barry, > > I'm afraid I'm not in a position to take a particularly > close look at this right now (on a rather slow net connection) > Thanks for taking a look at what we can unify. > > My immediate thought is that this patch may go a little too far, > certainly at this stage. =C2=A0It produces generic support for a > particular type of trigger (fine and useful) but I'm not > sure this should be grouped with the ring buffer setup elements. > There are plenty of devices that would benefit from parts of this > code, but currently it is all of the take it or leave it variety. > > In particular I'm not sure the ring buffer filling code should > be in here. =C2=A0It really isn't as consistent as the code implies > and by the presense of that element you have reduces the general > usefulness of rest. I'm very doubtful that we want to move things > like the rx and tx buffers out of the device drivers themselves. > The device drivers should control all access to the device, > not a core driver like this. Basically, rx and tx can be moved into the priv of iio_state. Or iio_state can be moved into iio_dev? Then this structure is not needed? > > Currently we don't have internal hooks to the contents > of the 'scans '. =C2=A0These could be added, but I think that would > add more complexity than simply allowing the drivers to handle > this aspect, not to mention adding some unecessary time penalty > to this path. > >> >> For iio core changes: >> 1. extract xxx_state to iio_state and add a private data to contain >> chip-specific data >> 2. extract all xxx_ring/xxx_trigger api to common api >> >> Index: drivers/staging/iio/iio.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/iio.h (revision 8893) >> +++ drivers/staging/iio/iio.h (working copy) >> @@ -447,4 +447,46 @@ >> >> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >> + >> +/** >> + * struct iio_state - hardware level hooks for iio device >> + * @work_trigger_to_ring: bh for triggered event handling >> + * @work_cont_thresh: CLEAN >> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if new inte= rrupt has been triggered >> + * @last_timestamp: =C2=A0passing timestamp from th to bh of interrupt = handler >> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 industr= ial I/O device structure >> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready trigger r= egistered with iio >> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0transmit buffer >> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0recieve buffer >> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mu= tex to protect tx and rx >> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0interru= pt number >> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the disab= le/enable of external interrupt >> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware by = spi/i2c. >> + **/ >> +struct iio_state { >> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 *parent_dev; >> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_trigger_to_ring; > >> + =C2=A0 =C2=A0 struct iio_work_cont =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0work_cont_thresh; >> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0*indio_dev; >> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0*trig; >> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; >> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); >> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); >> + =C2=A0 =C2=A0 void *priv; >> +}; >> + >> +static inline void iio_state_set_privdata(struct iio_state *st, void *d= ata) >> +{ >> + =C2=A0 =C2=A0 st->priv =3D data; >> +} >> + >> +static inline void * iio_state_get_privdata(struct iio_state *st) >> +{ >> + =C2=A0 =C2=A0 return st->priv; >> +} >> + >> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >> Index: drivers/staging/iio/common-ring-trigger.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >> @@ -0,0 +1,277 @@ >> +/* The software ring with trigger which can be used by most drivers >> + * >> + * Copyright (c) 2010 Barry Song >> + * >> + * This program is free software; you can redistribute it and/or modify= it >> + * under the terms of the GNU General Public License version 2 as publi= shed by >> + * the Free Software Foundation. >> + * >> + */ >> +#include <linux/kernel.h> >> +#include <linux/device.h> >> +#include <linux/interrupt.h> >> +#include <linux/fs.h> >> +#include <linux/poll.h> >> +#include <linux/module.h> >> +#include <linux/cdev.h> >> +#include <linux/slab.h> >> + >> +#include "iio.h" >> +#include "ring_generic.h" >> +#include "trigger.h" >> +#include "ring_sw.h" >> + >> +/* >> + * combine_8_to_16(): utility function to munge to u8s into u16 >> + */ >> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >> +{ >> + =C2=A0 =C2=A0 u16 _lower =3D lower; >> + =C2=A0 =C2=A0 u16 _upper =3D upper; >> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >> +} >> + >> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio_dev); >> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; >> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >> +} >> +/ > > This function is the one that mainly bothers me. =C2=A0We might > have a number of devices that do fit in here but there are > others that would use pretty much everything else but > this. =C2=A0I'd possibly be more inclined to leave this > to the drivers. =C2=A0That is where the knowledge about the > data layout in 'rx' comes from. Here we can let the hw_read_ring() do more, not only read hw, but also fill the last data buffer, like combine_8_to_16(). >> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_s, str= uct iio_state, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >> + >> + =C2=A0 =C2=A0 int i =3D 0; >> + =C2=A0 =C2=A0 s16 *data; >> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd(st->i= ndio_dev->ring); >> + >> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->par= ent_dev, "memory alloc failed in ring bh"); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, st-= >rx) >=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = for (; i < st->indio_dev->scan_count; i++) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 st->rx[i*2]); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = } >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte bou= ndary */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(data = + ((i + 3)/4)*4)) =3D st->last_timestamp; >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->in= dio_dev->ring, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(u8 *)data, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0st->last_timestamp); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->trig= ); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >> +} >> + >> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 size_t size; >> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, if not = fail*/ >> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_timestamp= )) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >> + >> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_timestam= p) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = if (indio_dev->scan_count) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * sizeof(s16)= ) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 & ~(sizeof(s64) - 1)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = else /* Timestamp only =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = size =3D indio_dev->scan_count*sizeof(s16); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->access.set_= bpd(indio_dev->ring, size); >> + =C2=A0 =C2=A0 } >> + >> + =C2=A0 =C2=A0 return 0; >> +} >> + >> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_a= ttach_poll_func(indio_dev->trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >> +} >> + >> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_d= ettach_poll_func(indio_dev->trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >> +} >> + >> +int iio_configure_common_ring(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 int ret =3D 0; >> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_= bh_to_ring); >> + >> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >> + =C2=A0 =C2=A0 if (!ring) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >> + >> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); >> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; >> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; >> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; >> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >> + >> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollf= unc), GFP_KERNEL); >> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_free;; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_common_ring= _poll_func_th; >> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >> + =C2=A0 =C2=A0 return 0; >> + >> +error_iio_sw_rb_free: >> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >> + =C2=A0 =C2=A0 return ret; >> +} >> +EXPORT_SYMBOL(iio_configure_common_ring); >> + >> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >> +} >> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >> + > This next one is pointless except possibly to unify > some naming so why do it? Just a copy-paste and rename for existing code. Here we can let driver call iio_ring_buffer_register/iio_ring_buffer_unregister directly? >> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >> +{ >> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >> +} >> +EXPORT_SYMBOL(iio_initialize_common_ring); >> + >> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >> +{ >> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >> +} >> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >> + >> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_info); >> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >> + >> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >> + >> + =C2=A0 =C2=A0 return IRQ_HANDLED; >> +} >> + >> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >> + >> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >> + >> +static struct attribute *iio_trigger_attrs[] =3D { >> + =C2=A0 =C2=A0 &dev_attr_name.attr, >> + =C2=A0 =C2=A0 NULL, >> +}; >> + >> +static const struct attribute_group iio_trigger_attr_group =3D { >> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >> +}; >> + >> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >> + =C2=A0 =C2=A0 enable_irq(st->irq); >> + =C2=A0 =C2=A0 return 0; >> +} >> + >> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >> + =C2=A0 =C2=A0 int ret =3D 0; >> + >> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); > This again is making some nasty assumptions. Yes some drivers > use a shared event to supply dat ready events, others do not > and if the line isn't shared they shouldn't as it adds a fair > bit of complexity to this fast path. you mean we should know the right interrupt line for data ready event if there are more than one indio_dev->interrupts elemant? >> + =C2=A0 =C2=A0 if (state =3D=3D false) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_list(&= iio_event_common_trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work(); >> + =C2=A0 =C2=A0 } else { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(&iio_e= vent_common_trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 return ret; >> +} >> + >> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 int ret; >> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >> + >> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_= KERNEL); >> + =C2=A0 =C2=A0 if (!st->trig->name) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = IIO_TRIGGER_NAME_LENGTH, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = "iio-dev%d", indio_dev->id); >> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigger_set_= state; >> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try_reen; >> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_group; >> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >> + >> + =C2=A0 =C2=A0 /* select default trigger */ >> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >> + =C2=A0 =C2=A0 if (ret) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_name; >> + >> + =C2=A0 =C2=A0 return 0; >> + >> +error_free_trig_name: >> + =C2=A0 =C2=A0 kfree(st->trig->name); >> +error_free_trig: >> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >> + >> + =C2=A0 =C2=A0 return ret; >> +} >> +EXPORT_SYMBOL(iio_probe_common_trigger); >> + >> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >> + >> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >> + =C2=A0 =C2=A0 kfree(state->trig->name); >> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >> +} >> +EXPORT_SYMBOL(iio_remove_common_trigger); >> Index: drivers/staging/iio/common-ring-trigger.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >> @@ -0,0 +1,24 @@ >> +/* The industrial I/O frequently used ring with trigger >> + * >> + * Copyright (c) 2010 Barry Song >> + * >> + * This program is free software; you can redistribute it and/or modify= it >> + * under the terms of the GNU General Public License version 2 as publi= shed by >> + * the Free Software Foundation. >> + * >> + */ >> + >> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >> +#define _IIO_COMMON_RING_TRIGGER_H_ >> + >> +#include "iio.h" >> +#include "ring_generic.h" >> + >> +int iio_configure_common_ring(struct iio_dev *indio_dev); >> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); >> + >> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >> Index: drivers/staging/iio/Kconfig >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (revision 8893) >> +++ drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (working copy) >> @@ -38,6 +38,12 @@ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ring buffers. =C2=A0The triggers are effecti= vely a 'capture >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 data now' interrupt. >> >> +config IIO_COMMON_RING_TRIGGER >> + =C2=A0 =C2=A0 boolean "Enable frequently used ring with trigger" >> + =C2=A0 =C2=A0 depends on IIO_SW_RING && IIO_TRIGGER >> + =C2=A0 =C2=A0 help >> + =C2=A0 =C2=A0 =C2=A0 Provides a generic ring with trigger. I can be us= ed by most >> + =C2=A0 =C2=A0 =C2=A0 IIO devices. >> >> =C2=A0source "drivers/staging/iio/accel/Kconfig" >> =C2=A0source "drivers/staging/iio/adc/Kconfig" >> Index: drivers/staging/iio/Makefile >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(revision 8893) >> +++ drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(working copy) >> @@ -9,6 +9,8 @@ >> >> =C2=A0obj-$(CONFIG_IIO_SW_RING) +=3D ring_sw.o >> >> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) +=3D common-ring-trigger.o >> + >> =C2=A0obj-y +=3D accel/ >> =C2=A0obj-y +=3D adc/ >> =C2=A0obj-y +=3D addac/ >> >> >> > > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-11 3:19 ` Barry Song @ 2010-06-11 10:22 ` Jonathan Cameron 2010-06-12 2:26 ` Barry Song 0 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-06-11 10:22 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/11/10 04:19, Barry Song wrote: > On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> On 06/10/10 05:48, Barry Song wrote: >>> Just RFC for discussion. It is not the last patch To keep the change >>> lest, i extract the common factor for most iio devices to a common >>> ring trigger module. Most devices can use the interfaces in this >>> module directly. So copy-paste for ring and trigger is not necessary >>> now. >> Hi Barry, >> >> I'm afraid I'm not in a position to take a particularly >> close look at this right now (on a rather slow net connection) >> Thanks for taking a look at what we can unify. >> >> My immediate thought is that this patch may go a little too far, >> certainly at this stage. It produces generic support for a >> particular type of trigger (fine and useful) but I'm not >> sure this should be grouped with the ring buffer setup elements. >> There are plenty of devices that would benefit from parts of this >> code, but currently it is all of the take it or leave it variety. >> >> In particular I'm not sure the ring buffer filling code should >> be in here. It really isn't as consistent as the code implies >> and by the presense of that element you have reduces the general >> usefulness of rest. I'm very doubtful that we want to move things >> like the rx and tx buffers out of the device drivers themselves. >> The device drivers should control all access to the device, >> not a core driver like this. > Basically, rx and tx can be moved into the priv of iio_state. Or > iio_state can be moved into iio_dev? Then this structure is not > needed? They could but I still think these should be part of the locale device driver state. I agree they don't need to be, but conceptualy to my mind everything to do with actual communications with the chip is not something the core (or helper modules like this one) should touch. >> >> Currently we don't have internal hooks to the contents >> of the 'scans '. These could be added, but I think that would >> add more complexity than simply allowing the drivers to handle >> this aspect, not to mention adding some unecessary time penalty >> to this path. >> >>> >>> For iio core changes: >>> 1. extract xxx_state to iio_state and add a private data to contain >>> chip-specific data >>> 2. extract all xxx_ring/xxx_trigger api to common api >>> >>> Index: drivers/staging/iio/iio.h >>> =================================================================== >>> --- drivers/staging/iio/iio.h (revision 8893) >>> +++ drivers/staging/iio/iio.h (working copy) >>> @@ -447,4 +447,46 @@ >>> >>> int iio_get_new_idr_val(struct idr *this_idr); >>> void iio_free_idr_val(struct idr *this_idr, int id); >>> + >>> +/** >>> + * struct iio_state - hardware level hooks for iio device >>> + * @work_trigger_to_ring: bh for triggered event handling >>> + * @work_cont_thresh: CLEAN >>> + * @inter: used to check if new interrupt has been triggered >>> + * @last_timestamp: passing timestamp from th to bh of interrupt handler >>> + * @indio_dev: industrial I/O device structure >>> + * @trig: data ready trigger registered with iio >>> + * @tx: transmit buffer >>> + * @rx: recieve buffer >>> + * @buf_lock: mutex to protect tx and rx >>> + * @irq: interrupt number >>> + * @set_irq: control the disable/enable of external interrupt >>> + * @hw_read_ring: read ring data from hardware by spi/i2c. >>> + **/ >>> +struct iio_state { >>> + struct device *parent_dev; >>> + struct work_struct work_trigger_to_ring; >> >>> + struct iio_work_cont work_cont_thresh; >>> + s64 last_timestamp; >>> + struct iio_dev *indio_dev; >>> + struct iio_trigger *trig; >>> + u8 *tx; >>> + u8 *rx; >>> + struct mutex buf_lock; >>> + int irq; >>> + int (*set_irq)(struct iio_state *st, bool enable); >>> + int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>> + void *priv; >>> +}; >>> + >>> +static inline void iio_state_set_privdata(struct iio_state *st, void *data) >>> +{ >>> + st->priv = data; >>> +} >>> + >>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>> +{ >>> + return st->priv; >>> +} >>> + >>> #endif /* _INDUSTRIAL_IO_H_ */ >>> Index: drivers/staging/iio/common-ring-trigger.c >>> =================================================================== >>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>> @@ -0,0 +1,277 @@ >>> +/* The software ring with trigger which can be used by most drivers >>> + * >>> + * Copyright (c) 2010 Barry Song >>> + * >>> + * This program is free software; you can redistribute it and/or modify it >>> + * under the terms of the GNU General Public License version 2 as published by >>> + * the Free Software Foundation. >>> + * >>> + */ >>> +#include <linux/kernel.h> >>> +#include <linux/device.h> >>> +#include <linux/interrupt.h> >>> +#include <linux/fs.h> >>> +#include <linux/poll.h> >>> +#include <linux/module.h> >>> +#include <linux/cdev.h> >>> +#include <linux/slab.h> >>> + >>> +#include "iio.h" >>> +#include "ring_generic.h" >>> +#include "trigger.h" >>> +#include "ring_sw.h" >>> + >>> +/* >>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>> + */ >>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>> +{ >>> + u16 _lower = lower; >>> + u16 _upper = upper; >>> + return _lower | (_upper << 8); >>> +} >>> + >>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>> +{ >>> + struct iio_state *st = iio_dev_get_devdata(indio_dev); >>> + st->last_timestamp = indio_dev->trig->timestamp; >>> + schedule_work(&st->work_trigger_to_ring); >>> +} >>> +/ >> >> This function is the one that mainly bothers me. We might >> have a number of devices that do fit in here but there are >> others that would use pretty much everything else but >> this. I'd possibly be more inclined to leave this >> to the drivers. That is where the knowledge about the >> data layout in 'rx' comes from. > > Here we can let the hw_read_ring() do more, not only read hw, but also > fill the last data buffer, like combine_8_to_16(). but once it is doing that much, what is te point of the following? You will save a few repeated lines, but at the cost of driver readability. I'm yet to be convinced that this function should exist. Why not pass the appropriate work struct in having initialized it in the chip driver? There are certainly elements of this code that will not be ideal for every device anyway (such as the kmalloc being in here!) > >>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>> +{ >>> + struct iio_state *st >>> + = container_of(work_s, struct iio_state, >>> + work_trigger_to_ring); >>> + >>> + int i = 0; >>> + s16 *data; >>> + size_t datasize = st->indio_dev >>> + ->ring->access.get_bpd(st->indio_dev->ring); >>> + >>> + data = kmalloc(datasize , GFP_KERNEL); >>> + if (data == NULL) { >>> + dev_err(st->parent_dev, "memory alloc failed in ring bh"); >>> + return; >>> + } >>> + >>> + if (st->indio_dev->scan_count) >>> + if (st->hw_read_ring(st, st->rx) >= 0) >>> + for (; i < st->indio_dev->scan_count; i++) { >>> + data[i] = combine_8_to_16(st->rx[i*2+1], >>> + st->rx[i*2]); >>> + } >>> + >>> + /* Guaranteed to be aligned with 8 byte boundary */ >>> + if (st->indio_dev->scan_timestamp) >>> + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; >>> + >>> + st->indio_dev->ring->access.store_to(st->indio_dev->ring, >>> + (u8 *)data, >>> + st->last_timestamp); >>> + >>> + iio_trigger_notify_done(st->indio_dev->trig); >>> + kfree(data); >>> + >>> + return; >>> +} >>> + >>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>> +{ >>> + size_t size; >>> + dev_dbg(&indio_dev->dev, "%s\n", __func__); >>> + /* Check if there are any scan elements enabled, if not fail*/ >>> + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) >>> + return -EINVAL; >>> + >>> + if (indio_dev->ring->access.set_bpd) { >>> + if (indio_dev->scan_timestamp) >>> + if (indio_dev->scan_count) >>> + /* Timestamp (aligned to s64) and data */ >>> + size = (((indio_dev->scan_count * sizeof(s16)) >>> + + sizeof(s64) - 1) >>> + & ~(sizeof(s64) - 1)) >>> + + sizeof(s64); >>> + else /* Timestamp only */ >>> + size = sizeof(s64); >>> + else /* Data only */ >>> + size = indio_dev->scan_count*sizeof(s16); >>> + indio_dev->ring->access.set_bpd(indio_dev->ring, size); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>> +{ >>> + return indio_dev->trig >>> + ? iio_trigger_attach_poll_func(indio_dev->trig, >>> + indio_dev->pollfunc) >>> + : 0; >>> +} >>> + >>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>> +{ >>> + return indio_dev->trig >>> + ? iio_trigger_dettach_poll_func(indio_dev->trig, >>> + indio_dev->pollfunc) >>> + : 0; >>> +} >>> + >>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>> +{ >>> + int ret = 0; >>> + struct iio_state *st = indio_dev->dev_data; >>> + struct iio_ring_buffer *ring; >>> + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); >>> + >>> + ring = iio_sw_rb_allocate(indio_dev); >>> + if (!ring) { >>> + ret = -ENOMEM; >>> + return ret; >>> + } >>> + indio_dev->ring = ring; >>> + >>> + iio_ring_sw_register_funcs(&ring->access); >>> + ring->preenable = &iio_common_ring_preenable; >>> + ring->postenable = &iio_common_ring_postenable; >>> + ring->predisable = &iio_common_ring_predisable; >>> + ring->owner = THIS_MODULE; >>> + >>> + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); >>> + if (indio_dev->pollfunc == NULL) { >>> + ret = -ENOMEM; >>> + goto error_iio_sw_rb_free;; >>> + } >>> + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; >>> + indio_dev->pollfunc->private_data = indio_dev; >>> + indio_dev->modes |= INDIO_RING_TRIGGERED; >>> + return 0; >>> + >>> +error_iio_sw_rb_free: >>> + iio_sw_rb_free(indio_dev->ring); >>> + return ret; >>> +} >>> +EXPORT_SYMBOL(iio_configure_common_ring); >>> + >>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>> +{ >>> + kfree(indio_dev->pollfunc); >>> + iio_sw_rb_free(indio_dev->ring); >>> +} >>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>> + >> This next one is pointless except possibly to unify >> some naming so why do it? > Just a copy-paste and rename for existing code. Here we can let driver > call iio_ring_buffer_register/iio_ring_buffer_unregister directly? exactly. >>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>> +{ >>> + return iio_ring_buffer_register(ring, 0); >>> +} >>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>> + >>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>> +{ >>> + iio_ring_buffer_unregister(ring); >>> +} >>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>> + >>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>> + int index, >>> + s64 timestamp, >>> + int no_test) >>> +{ >>> + struct iio_state *st = iio_dev_get_devdata(dev_info); >>> + struct iio_trigger *trig = st->trig; >>> + >>> + trig->timestamp = timestamp; >>> + iio_trigger_poll(trig); >>> + >>> + return IRQ_HANDLED; >>> +} >>> + >>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>> + >>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>> + >>> +static struct attribute *iio_trigger_attrs[] = { >>> + &dev_attr_name.attr, >>> + NULL, >>> +}; >>> + >>> +static const struct attribute_group iio_trigger_attr_group = { >>> + .attrs = iio_trigger_attrs, >>> +}; >>> + >>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>> +{ >>> + struct iio_state *st = trig->private_data; >>> + enable_irq(st->irq); >>> + return 0; >>> +} >>> + >>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>> + bool state) >>> +{ >>> + struct iio_state *st = trig->private_data; >>> + struct iio_dev *indio_dev = st->indio_dev; >>> + int ret = 0; >>> + >>> + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >>> + ret = st->set_irq(st, state); >> This again is making some nasty assumptions. Yes some drivers >> use a shared event to supply dat ready events, others do not >> and if the line isn't shared they shouldn't as it adds a fair >> bit of complexity to this fast path. > you mean we should know the right interrupt line for data ready event > if there are more than one indio_dev->interrupts elemant? no. I meant that indio_dev->interrupts is meant to be NULL in those cases where the only interrupt (on a given line) is used for triggering. The situation used here is only meant to occur if the same line may indicate data ready or say a threshold interrupt and has to check which it is. If we only have a dataready signal this path adds considerably complexity for no reason. The reason I didn't comment on this in your drivers is that I assumed that event functionality was in the works. As it currently stands none of them should be using this method, they should all be using and handling the interrupt directly. The reason this complexity exists in the lis3l02dq is that it only has a single physical interrupt line an this is shared between data ready and theshold events. In my original adis16350 I dedicated one line to the alarms and one to the data ready. Obviously this is a bit restrictive on possible wiring so it may make sense to go the more complex route in software. > >>> + if (state == false) { >>> + iio_remove_event_from_list(&iio_event_common_trig, >>> + &indio_dev->interrupts[0] >>> + ->ev_list); >>> + flush_scheduled_work(); >>> + } else { >>> + iio_add_event_to_list(&iio_event_common_trig, >>> + &indio_dev->interrupts[0]->ev_list); >>> + } >>> + return ret; >>> +} >>> + >>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>> +{ >>> + int ret; >>> + struct iio_state *st = indio_dev->dev_data; >>> + >>> + st->trig = iio_allocate_trigger(); >>> + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); >>> + if (!st->trig->name) { >>> + ret = -ENOMEM; >>> + goto error_free_trig; >>> + } >>> + snprintf((char *)st->trig->name, >>> + IIO_TRIGGER_NAME_LENGTH, >>> + "iio-dev%d", indio_dev->id); >>> + st->trig->dev.parent = st->parent_dev; >>> + st->trig->owner = THIS_MODULE; >>> + st->trig->private_data = st; >>> + st->trig->set_trigger_state = &iio_common_trigger_set_state; >>> + st->trig->try_reenable = &iio_common_trigger_try_reen; >>> + st->trig->control_attrs = &iio_trigger_attr_group; >>> + ret = iio_trigger_register(st->trig); >>> + >>> + /* select default trigger */ >>> + indio_dev->trig = st->trig; >>> + if (ret) >>> + goto error_free_trig_name; >>> + >>> + return 0; >>> + >>> +error_free_trig_name: >>> + kfree(st->trig->name); >>> +error_free_trig: >>> + iio_free_trigger(st->trig); >>> + >>> + return ret; >>> +} >>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>> + >>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>> +{ >>> + struct iio_state *state = indio_dev->dev_data; >>> + >>> + iio_trigger_unregister(state->trig); >>> + kfree(state->trig->name); >>> + iio_free_trigger(state->trig); >>> +} >>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>> Index: drivers/staging/iio/common-ring-trigger.h >>> =================================================================== >>> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >>> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >>> @@ -0,0 +1,24 @@ >>> +/* The industrial I/O frequently used ring with trigger >>> + * >>> + * Copyright (c) 2010 Barry Song >>> + * >>> + * This program is free software; you can redistribute it and/or modify it >>> + * under the terms of the GNU General Public License version 2 as published by >>> + * the Free Software Foundation. >>> + * >>> + */ >>> + >>> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >>> +#define _IIO_COMMON_RING_TRIGGER_H_ >>> + >>> +#include "iio.h" >>> +#include "ring_generic.h" >>> + >>> +int iio_configure_common_ring(struct iio_dev *indio_dev); >>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); >>> + >>> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >>> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >>> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >>> Index: drivers/staging/iio/Kconfig >>> =================================================================== >>> --- drivers/staging/iio/Kconfig (revision 8893) >>> +++ drivers/staging/iio/Kconfig (working copy) >>> @@ -38,6 +38,12 @@ >>> ring buffers. The triggers are effectively a 'capture >>> data now' interrupt. >>> >>> +config IIO_COMMON_RING_TRIGGER >>> + boolean "Enable frequently used ring with trigger" >>> + depends on IIO_SW_RING && IIO_TRIGGER >>> + help >>> + Provides a generic ring with trigger. I can be used by most >>> + IIO devices. >>> >>> source "drivers/staging/iio/accel/Kconfig" >>> source "drivers/staging/iio/adc/Kconfig" >>> Index: drivers/staging/iio/Makefile >>> =================================================================== >>> --- drivers/staging/iio/Makefile (revision 8893) >>> +++ drivers/staging/iio/Makefile (working copy) >>> @@ -9,6 +9,8 @@ >>> >>> obj-$(CONFIG_IIO_SW_RING) += ring_sw.o >>> >>> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) += common-ring-trigger.o >>> + >>> obj-y += accel/ >>> obj-y += adc/ >>> obj-y += addac/ >>> >>> >>> >> >> >> > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-11 10:22 ` Jonathan Cameron @ 2010-06-12 2:26 ` Barry Song 2010-06-12 17:35 ` Jonathan Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-12 2:26 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 The driver doesn't aim to replace what has existed in iio core. Just improvement and a module which can be shared by most devices. Devices which have special path can still self-define like before. On Fri, Jun 11, 2010 at 6:22 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 06/11/10 04:19, Barry Song wrote: >> On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk> wrot= e: >>> On 06/10/10 05:48, Barry Song wrote: >>>> Just RFC for discussion. It is not the last patch To keep the change >>>> lest, i extract the common factor for most iio devices to a common >>>> ring trigger module. Most devices can use the interfaces in this >>>> module directly. So copy-paste for ring and trigger is not necessary >>>> now. >>> Hi Barry, >>> >>> I'm afraid I'm not in a position to take a particularly >>> close look at this right now (on a rather slow net connection) >>> Thanks for taking a look at what we can unify. >>> >>> My immediate thought is that this patch may go a little too far, >>> certainly at this stage. =C2=A0It produces generic support for a >>> particular type of trigger (fine and useful) but I'm not >>> sure this should be grouped with the ring buffer setup elements. >>> There are plenty of devices that would benefit from parts of this >>> code, but currently it is all of the take it or leave it variety. >>> >>> In particular I'm not sure the ring buffer filling code should >>> be in here. =C2=A0It really isn't as consistent as the code implies >>> and by the presense of that element you have reduces the general >>> usefulness of rest. I'm very doubtful that we want to move things >>> like the rx and tx buffers out of the device drivers themselves. >>> The device drivers should control all access to the device, >>> not a core driver like this. >> Basically, rx and tx can be moved into the priv of iio_state. Or >> iio_state can be moved into iio_dev? Then this structure is not >> needed? > They could but I still think these should be part of the locale > device driver state. I agree they don't need to be, but conceptualy > to my mind everything to do with actual communications with the chip > is not something the core (or helper modules like this one) should > touch. The bottom level hardware read/write can be part of the device driver. But the flow can be in the core. The iio_state is derived from objects like nand_chip, nand_base can handle data flow, the bottom_level nand driver just fill the last hardware access entries. >>> >>> Currently we don't have internal hooks to the contents >>> of the 'scans '. =C2=A0These could be added, but I think that would >>> add more complexity than simply allowing the drivers to handle >>> this aspect, not to mention adding some unecessary time penalty >>> to this path. >>> >>>> >>>> For iio core changes: >>>> 1. extract xxx_state to iio_state and add a private data to contain >>>> chip-specific data >>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>> >>>> Index: drivers/staging/iio/iio.h >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/iio.h (revision 8893) >>>> +++ drivers/staging/iio/iio.h (working copy) >>>> @@ -447,4 +447,46 @@ >>>> >>>> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >>>> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >>>> + >>>> +/** >>>> + * struct iio_state - hardware level hooks for iio device >>>> + * @work_trigger_to_ring: bh for triggered event handling >>>> + * @work_cont_thresh: CLEAN >>>> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if new in= terrupt has been triggered >>>> + * @last_timestamp: =C2=A0passing timestamp from th to bh of interrup= t handler >>>> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indus= trial I/O device structure >>>> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready trigger= registered with iio >>>> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0transmit buffer >>>> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0recieve buffer >>>> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= mutex to protect tx and rx >>>> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0inter= rupt number >>>> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the dis= able/enable of external interrupt >>>> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware b= y spi/i2c. >>>> + **/ >>>> +struct iio_state { >>>> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 *parent_dev; >>>> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_trigger_to_ring; >>> >>>> + =C2=A0 =C2=A0 struct iio_work_cont =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0work_cont_thresh; >>>> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >>>> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0*indio_dev; >>>> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0*trig; >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >>>> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; >>>> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >>>> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); >>>> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>>> + =C2=A0 =C2=A0 void *priv; >>>> +}; >>>> + >>>> +static inline void iio_state_set_privdata(struct iio_state *st, void = *data) >>>> +{ >>>> + =C2=A0 =C2=A0 st->priv =3D data; >>>> +} >>>> + >>>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>>> +{ >>>> + =C2=A0 =C2=A0 return st->priv; >>>> +} >>>> + >>>> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >>>> Index: drivers/staging/iio/common-ring-trigger.c >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> @@ -0,0 +1,277 @@ >>>> +/* The software ring with trigger which can be used by most drivers >>>> + * >>>> + * Copyright (c) 2010 Barry Song >>>> + * >>>> + * This program is free software; you can redistribute it and/or modi= fy it >>>> + * under the terms of the GNU General Public License version 2 as pub= lished by >>>> + * the Free Software Foundation. >>>> + * >>>> + */ >>>> +#include <linux/kernel.h> >>>> +#include <linux/device.h> >>>> +#include <linux/interrupt.h> >>>> +#include <linux/fs.h> >>>> +#include <linux/poll.h> >>>> +#include <linux/module.h> >>>> +#include <linux/cdev.h> >>>> +#include <linux/slab.h> >>>> + >>>> +#include "iio.h" >>>> +#include "ring_generic.h" >>>> +#include "trigger.h" >>>> +#include "ring_sw.h" >>>> + >>>> +/* >>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>> + */ >>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>> +{ >>>> + =C2=A0 =C2=A0 u16 _lower =3D lower; >>>> + =C2=A0 =C2=A0 u16 _upper =3D upper; >>>> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >>>> +} >>>> + >>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio_dev= ); >>>> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; >>>> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >>>> +} >>>> +/ >>> >>> This function is the one that mainly bothers me. =C2=A0We might >>> have a number of devices that do fit in here but there are >>> others that would use pretty much everything else but >>> this. =C2=A0I'd possibly be more inclined to leave this >>> to the drivers. =C2=A0That is where the knowledge about the >>> data layout in 'rx' comes from. >> >> Here we can let the hw_read_ring() do more, not only read hw, but also >> fill the last data buffer, like combine_8_to_16(). > but once it is doing that much, what is te point of the following? > You will save a few repeated lines, but at the cost of driver > readability. I'm yet to be convinced that this function should exist. > Why not pass the appropriate work struct in having initialized it > in the chip driver? =C2=A0There are certainly elements of this code that > will not be ideal for every device anyway (such as the kmalloc > being in here!) not just several saved lines. But mean the bottom level driver doesn't need to care the flow of trigger_bh_to_ring(). Bottom level driver doesn't need to self-define its trigger_bh_to_ring(), it only read hardware data and fill the data buffer. That's what the bottom level driver wants to do. >> >>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_s, s= truct iio_state, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >>>> + >>>> + =C2=A0 =C2=A0 int i =3D 0; >>>> + =C2=A0 =C2=A0 s16 *data; >>>> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd(st-= >indio_dev->ring); >>>> + >>>> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->p= arent_dev, "memory alloc failed in ring bh"); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >>>> + >>>> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, s= t->rx) >=3D 0) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 for (; i < st->indio_dev->scan_count; i++) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 st->rx[i*2]); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 } >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte b= oundary */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(dat= a + ((i + 3)/4)*4)) =3D st->last_timestamp; >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->= indio_dev->ring, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0(u8 *)data, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0st->last_timestamp); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->tr= ig); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> +} >>>> + >>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 size_t size; >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, if no= t fail*/ >>>> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_timesta= mp)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >>>> + >>>> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_timest= amp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 if (indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * sizeof(= s16)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 & ~(sizeof(s64) - 1)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 else /* Timestamp only =C2=A0*/ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 size =3D indio_dev->scan_count*sizeof(s16); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->access.se= t_bpd(indio_dev->ring, size); >>>> + =C2=A0 =C2=A0 } >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _attach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>>> + >>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _dettach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>>> + >>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >>>> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_trigge= r_bh_to_ring); >>>> + >>>> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >>>> + =C2=A0 =C2=A0 if (!ring) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >>>> + >>>> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); >>>> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; >>>> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; >>>> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; >>>> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >>>> + >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pol= lfunc), GFP_KERNEL); >>>> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_free;= ; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_common_ri= ng_poll_func_th; >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >>>> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_iio_sw_rb_free: >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>> + >>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>> + >>> This next one is pointless except possibly to unify >>> some naming so why do it? >> Just a copy-paste and rename for existing code. Here we can let driver >> call =C2=A0iio_ring_buffer_register/iio_ring_buffer_unregister directly? > exactly. >>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >>>> +} >>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>> + >>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>> + >>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_info)= ; >>>> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >>>> + >>>> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >>>> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >>>> + >>>> + =C2=A0 =C2=A0 return IRQ_HANDLED; >>>> +} >>>> + >>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>>> + >>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>> + >>>> +static struct attribute *iio_trigger_attrs[] =3D { >>>> + =C2=A0 =C2=A0 &dev_attr_name.attr, >>>> + =C2=A0 =C2=A0 NULL, >>>> +}; >>>> + >>>> +static const struct attribute_group iio_trigger_attr_group =3D { >>>> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >>>> +}; >>>> + >>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 enable_irq(st->irq); >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state)= ; >>>> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); >>> This again is making some nasty assumptions. Yes some drivers >>> use a shared event to supply dat ready events, others do not >>> and if the line isn't shared they shouldn't as it adds a fair >>> bit of complexity to this fast path. >> you mean we should know the right interrupt line for data ready event >> if there are more than one indio_dev->interrupts elemant? > > no. I meant that indio_dev->interrupts is meant to be NULL in those > cases where the only interrupt (on a given line) is used for triggering. > The situation > used here is only meant to occur if the same line may indicate data > ready or say a threshold interrupt and has to check which it is. > If we only have a dataready signal this path adds considerably > complexity for no reason. =C2=A0The reason I didn't comment on this in > your drivers is that I assumed that event functionality was in the > works. =C2=A0As it currently stands none of them should be using this > method, they should all be using and handling the interrupt directly. > The reason this complexity exists in the lis3l02dq is that it only > has a single physical interrupt line an this is shared between data > ready and theshold events. =C2=A0In my original adis16350 I dedicated > one line to the alarms and one to the data ready. =C2=A0Obviously this > is a bit restrictive on possible wiring so it may make sense to go > the more complex route in software. >> >>>> + =C2=A0 =C2=A0 if (state =3D=3D false) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_list= (&iio_event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work(); >>>> + =C2=A0 =C2=A0 } else { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(&iio= _event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> + >>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >>>> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GF= P_KERNEL); >>>> + =C2=A0 =C2=A0 if (!st->trig->name) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 IIO_TRIGGER_NAME_LENGTH, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "iio-dev%d", indio_dev->id); >>>> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >>>> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >>>> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >>>> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigger_se= t_state; >>>> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try_ree= n; >>>> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_group; >>>> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 /* select default trigger */ >>>> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >>>> + =C2=A0 =C2=A0 if (ret) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_name; >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_free_trig_name: >>>> + =C2=A0 =C2=A0 kfree(st->trig->name); >>>> +error_free_trig: >>>> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>> + >>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >>>> + =C2=A0 =C2=A0 kfree(state->trig->name); >>>> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >>>> +} >>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>>> Index: drivers/staging/iio/common-ring-trigger.h >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >>>> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >>>> @@ -0,0 +1,24 @@ >>>> +/* The industrial I/O frequently used ring with trigger >>>> + * >>>> + * Copyright (c) 2010 Barry Song >>>> + * >>>> + * This program is free software; you can redistribute it and/or modi= fy it >>>> + * under the terms of the GNU General Public License version 2 as pub= lished by >>>> + * the Free Software Foundation. >>>> + * >>>> + */ >>>> + >>>> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >>>> +#define _IIO_COMMON_RING_TRIGGER_H_ >>>> + >>>> +#include "iio.h" >>>> +#include "ring_generic.h" >>>> + >>>> +int iio_configure_common_ring(struct iio_dev *indio_dev); >>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); >>>> + >>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >>>> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >>>> Index: drivers/staging/iio/Kconfig >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (revision 8893) >>>> +++ drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (working copy) >>>> @@ -38,6 +38,12 @@ >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ring buffers. =C2=A0The triggers are effec= tively a 'capture >>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 data now' interrupt. >>>> >>>> +config IIO_COMMON_RING_TRIGGER >>>> + =C2=A0 =C2=A0 boolean "Enable frequently used ring with trigger" >>>> + =C2=A0 =C2=A0 depends on IIO_SW_RING && IIO_TRIGGER >>>> + =C2=A0 =C2=A0 help >>>> + =C2=A0 =C2=A0 =C2=A0 Provides a generic ring with trigger. I can be = used by most >>>> + =C2=A0 =C2=A0 =C2=A0 IIO devices. >>>> >>>> =C2=A0source "drivers/staging/iio/accel/Kconfig" >>>> =C2=A0source "drivers/staging/iio/adc/Kconfig" >>>> Index: drivers/staging/iio/Makefile >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(revision 8893) >>>> +++ drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(working copy) >>>> @@ -9,6 +9,8 @@ >>>> >>>> =C2=A0obj-$(CONFIG_IIO_SW_RING) +=3D ring_sw.o >>>> >>>> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) +=3D common-ring-trigger.o >>>> + >>>> =C2=A0obj-y +=3D accel/ >>>> =C2=A0obj-y +=3D adc/ >>>> =C2=A0obj-y +=3D addac/ >>>> >>>> >>>> >>> >>> >>> >> > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-12 2:26 ` Barry Song @ 2010-06-12 17:35 ` Jonathan Cameron 2010-06-21 9:21 ` Barry Song 0 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-06-12 17:35 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/12/10 03:26, Barry Song wrote: Hi Barry, I'm afraid I'm still on a useless net connection so don't have option to review the code properly. > The driver doesn't aim to replace what has existed in iio core. Just > improvement and a module which can be shared by most devices. Devices > which have special path can still self-define like before. Indeed, this is a good idea. I'm just disagreeing with a few of the details. As things stand with this patch at the mo, its a take it or leave it situation. I'd like to have it so drivers can cherry pick those elements they want as that will give us the most advantages. > > On Fri, Jun 11, 2010 at 6:22 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> On 06/11/10 04:19, Barry Song wrote: >>> On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >>>> On 06/10/10 05:48, Barry Song wrote: >>>>> Just RFC for discussion. It is not the last patch To keep the change >>>>> lest, i extract the common factor for most iio devices to a common >>>>> ring trigger module. Most devices can use the interfaces in this >>>>> module directly. So copy-paste for ring and trigger is not necessary >>>>> now. >>>> Hi Barry, >>>> >>>> I'm afraid I'm not in a position to take a particularly >>>> close look at this right now (on a rather slow net connection) >>>> Thanks for taking a look at what we can unify. >>>> >>>> My immediate thought is that this patch may go a little too far, >>>> certainly at this stage. It produces generic support for a >>>> particular type of trigger (fine and useful) but I'm not >>>> sure this should be grouped with the ring buffer setup elements. >>>> There are plenty of devices that would benefit from parts of this >>>> code, but currently it is all of the take it or leave it variety. >>>> >>>> In particular I'm not sure the ring buffer filling code should >>>> be in here. It really isn't as consistent as the code implies >>>> and by the presense of that element you have reduces the general >>>> usefulness of rest. I'm very doubtful that we want to move things >>>> like the rx and tx buffers out of the device drivers themselves. >>>> The device drivers should control all access to the device, >>>> not a core driver like this. >>> Basically, rx and tx can be mo/ved into the priv of iio_state. Or >>> iio_state can be moved into iio_dev? Then this structure is not >>> needed? >> They could but I still think these should be part of the locale >> device driver state. I agree they don't need to be, but conceptualy >> to my mind everything to do with actual communications with the chip >> is not something the core (or helper modules like this one) should >> touch. > The bottom level hardware read/write can be part of the device driver. > But the flow can be in the core. > The iio_state is derived from objects like nand_chip, nand_base can > handle data flow, the bottom_level nand driver just fill the last > hardware access entries. Exactly, but in there case they have a pretty good idea of what is coming down the line. Here we don't, so i would prefer to see the separation being at the level of driver gets data and pushes to the core (in this case the buffer) rather than your proposal to insert another layer pulling from the driver and pushing to the core. I agree there looks to be a lot of shared code in various drivers and it is nice to get rid of it where possible. However this should be constrained by the need to maintain readability of the code. In this particular case (just the buffer filling function not the rest which looks pretty good to me!) I think we loose clarity to save few lines. My proposal is that, rather than passing your low level get data function to the handling code, just step up one level and pass the work struct (or related function) instead. Thus all device related manipulation remains in the device driver, and we still get the benefit of saving on a lot of replication. The principle issue here is that, even with your patch the core doesn't know anywhere near enough about the incoming data from the chip. It currently has access to how many channels there are and whether there is a timestamp. To do the buffer fill it would need to know: 1) Offsets in raw data coming off the chip (common case is to start all reads with a status byte - to get rid of this in your current code involve an extra copy of all data) 2) The size of each element being read back. 3) Packing of the data I can see your point that your current driver covers a number of devices that we already have drivers for. My issue is that with this one element removed it covers pretty much any device with a dataready trigger. That seems like a bigger gain to me. If we divide things a little further, separating the ring buffer related elements and the trigger related elements then some elements are useful to every driver with a software buffer. It is that gain that would be most beneficial. >>>> >>>> Currently we don't have internal hooks to the contents >>>> of the 'scans '. These could be added, but I think that would >>>> add more complexity than simply allowing the drivers to handle >>>> this aspect, not to mention adding some unecessary time penalty >>>> to this path. >>>> >>>>> >>>>> For iio core changes: >>>>> 1. extract xxx_state to iio_state and add a private data to contain >>>>> chip-specific data >>>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>>> >>>>> Index: drivers/staging/iio/iio.h >>>>> =================================================================== >>>>> --- drivers/staging/iio/iio.h (revision 8893) >>>>> +++ drivers/staging/iio/iio.h (working copy) >>>>> @@ -447,4 +447,46 @@ >>>>> >>>>> int iio_get_new_idr_val(struct idr *this_idr); >>>>> void iio_free_idr_val(struct idr *this_idr, int id); >>>>> + >>>>> +/** >>>>> + * struct iio_state - hardware level hooks for iio device >>>>> + * @work_trigger_to_ring: bh for triggered event handling >>>>> + * @work_cont_thresh: CLEAN >>>>> + * @inter: used to check if new interrupt has been triggered >>>>> + * @last_timestamp: passing timestamp from th to bh of interrupt handler >>>>> + * @indio_dev: industrial I/O device structure >>>>> + * @trig: data ready trigger registered with iio >>>>> + * @tx: transmit buffer >>>>> + * @rx: recieve buffer >>>>> + * @buf_lock: mutex to protect tx and rx >>>>> + * @irq: interrupt number >>>>> + * @set_irq: control the disable/enable of external interrupt >>>>> + * @hw_read_ring: read ring data from hardware by spi/i2c. >>>>> + **/ >>>>> +struct iio_state { >>>>> + struct device *parent_dev >>>>> + struct work_struct work_trigger_to_ring; >>>> Whilst we are here, note the recent patch to remove work_cont structure. We have nothing that currently needs it so it shouldn't be here. >>>>> + struct iio_work_cont work_cont_thresh; >>>>> + s64 last_timestamp; >>>>> + struct iio_dev *indio_dev; >>>>> + struct iio_trigger *trig; >>>>> + u8 *tx; >>>>> + u8 *rx; >>>>> + struct mutex buf_lock; >>>>> + int irq; >>>>> + int (*set_irq)(struct iio_state *st, bool enable); >>>>> + int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>>>> + void *priv; >>>>> +}; >>>>> + >>>>> +static inline void iio_state_set_privdata(struct iio_state *st, void *data) >>>>> +{ >>>>> + st->priv = data; >>>>> +} >>>>> + >>>>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>>>> +{ >>>>> + return st->priv; >>>>> +} >>>>> + >>>>> #endif /* _INDUSTRIAL_IO_H_ */ >>>>> Index: drivers/staging/iio/common-ring-trigger.c >>>>> =================================================================== >>>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>> @@ -0,0 +1,277 @@ >>>>> +/* The software ring with trigger which can be used by most drivers >>>>> + * >>>>> + * Copyright (c) 2010 Barry Song >>>>> + * >>>>> + * This program is free software; you can redistribute it and/or modify it >>>>> + * under the terms of the GNU General Public License version 2 as published by >>>>> + * the Free Software Foundation. >>>>> + * >>>>> + */ >>>>> +#include <linux/kernel.h> >>>>> +#include <linux/device.h> >>>>> +#include <linux/interrupt.h> >>>>> +#include <linux/fs.h> >>>>> +#include <linux/poll.h> >>>>> +#include <linux/module.h> >>>>> +#include <linux/cdev.h> >>>>> +#include <linux/slab.h> >>>>> + >>>>> +#include "iio.h" >>>>> +#include "ring_generic.h" >>>>> +#include "trigger.h" >>>>> +#include "ring_sw.h" >>>>> + >>>>> +/* >>>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>>> + */ >>>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>>> +{ >>>>> + u16 _lower = lower; >>>>> + u16 _upper = upper; >>>>> + return _lower | (_upper << 8); >>>>> +} >>>>> + >>>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>>>> +{ >>>>> + struct iio_state *st = iio_dev_get_devdata(indio_dev); >>>>> + st->last_timestamp = indio_dev->trig->timestamp; >>>>> + schedule_work(&st->work_trigger_to_ring); >>>>> +} >>>>> +/ >>>> >>>> This function is the one that mainly bothers me. We might >>>> have a number of devices that do fit in here but there are >>>> others that would use pretty much everything else but >>>> this. I'd possibly be more inclined to leave this >>>> to the drivers. That is where the knowledge about the >>>> data layout in 'rx' comes from. >>> >>> Here we can let the hw_read_ring() do more, not only read hw, but also >>> fill the last data buffer, like combine_8_to_16(). >> but once it is doing that much, what is te point of the following? >> You will save a few repeated lines, but at the cost of driver >> readability. I'm yet to be convinced that this function should exist. >> Why not pass the appropriate work struct in having initialized it >> in the chip driver? There are certainly elements of this code that >> will not be ideal for every device anyway (such as the kmalloc >> being in here!) > not just several saved lines. But mean the bottom level driver doesn't > need to care the flow of trigger_bh_to_ring(). > Bottom level driver doesn't need to self-define its > trigger_bh_to_ring(), it only read hardware data and fill the data > buffer. That's what the bottom level driver wants to do. I agree that has a certain elegance, but unfortunately the bottom level driver is still responsible for telling userspace what is in the buffer. Thus I am yet to be convinced it shouldn't also be responsible for filling the buffer. If we really want to hide this from the device, then the following would work //Ask the driver for a suitably aligned pointer to the data u8 *dat = iio_dev.get_data_for_buffer(u8 alignment); ring.push_to_ring(dat); iio_dev.notify_buffer_data_done(); Or (and this approach is needed if a device can use the buffer elements directly for dma). u8 *data = ring.allocate_data(sizeofdata); iio_dev.get_data_for_buffer(data); ring.notify_filled(); Perhaps we should leave this element as one that need more thought / debate and push on with the others. Also worth noting is that pretty much all these dataready triggers will not currently work if 'only' another device is using them as a trigger. (nothing clears the interrupt). It may seem to be a fairly odd thing to do, and I'm still wondering if it is better to insist this should work in all drivers, or to actively prevent it. Both options are non trivial. Looking more at the functions covered I'm not sure that it wouldn't be better to just provide the useful ones as 'library functions' that a driver can cherry pick it they are applicable or in some cases make the the default with the option to override deliberately for cases they do not cover. >>> >>>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>>>> +{ >>>>> + struct iio_state *st >>>>> + = container_of(work_s, struct iio_state, >>>>> + work_trigger_to_ring); >>>>> + >>>>> + int i = 0; >>>>> + s16 *data; >>>>> + size_t datasize = st->indio_dev >>>>> + ->ring->access.get_bpd(st->indio_dev->ring); >>>>> + >>>>> + data = kmalloc(datasize , GFP_KERNEL); >>>>> + if (data == NULL) { >>>>> + dev_err(st->parent_dev, "memory alloc failed in ring bh"); >>>>> + return; >>>>> + } >>>>> + >>>>> + if (st->indio_dev->scan_count) >>>>> + if (st->hw_read_ring(st, st->rx) >= 0) >>>>> + for (; i < st->indio_dev->scan_count; i++) { >>>>> + data[i] = combine_8_to_16(st->rx[i*2+1], >>>>> + st->rx[i*2]); >>>>> + } >>>>> + >>>>> + /* Guaranteed to be aligned with 8 byte boundary */ >>>>> + if (st->indio_dev->scan_timestamp) >>>>> + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; >>>>> + >>>>> + st->indio_dev->ring->access.store_to(st->indio_dev->ring, >>>>> + (u8 *)data, >>>>> + st->last_timestamp); >>>>> + >>>>> + iio_trigger_notify_done(st->indio_dev->trig); >>>>> + kfree(data); >>>>> + >>>>> + return; >>>>> +} >>>>> + >>>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>>> +{ >>>>> + size_t size; >>>>> + dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>>> + /* Check if there are any scan elements enabled, if not fail*/ >>>>> + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) >>>>> + return -EINVAL; >>>>> + >>>>> + if (indio_dev->ring->access.set_bpd) { >>>>> + if (indio_dev->scan_timestamp) >>>>> + if (indio_dev->scan_count) >>>>> + /* Timestamp (aligned to s64) and data */ >>>>> + size = (((indio_dev->scan_count * sizeof(s16)) >>>>> + + sizeof(s64) - 1) >>>>> + & ~(sizeof(s64) - 1)) >>>>> + + sizeof(s64); >>>>> + else /* Timestamp only */ >>>>> + size = sizeof(s64); >>>>> + else /* Data only */ >>>>> + size = indio_dev->scan_count*sizeof(s16); >>>>> + indio_dev->ring->access.set_bpd(indio_dev->ring, size); >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>>>> +{ >>>>> + return indio_dev->trig >>>>> + ? iio_trigger_attach_poll_func(indio_dev->trig, >>>>> + indio_dev->pollfunc) >>>>> + : 0; >>>>> +} >>>>> + >>>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>>>> +{ >>>>> + return indio_dev->trig >>>>> + ? iio_trigger_dettach_poll_func(indio_dev->trig, >>>>> + indio_dev->pollfunc) >>>>> + : 0; >>>>> +} >>>>> + >>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>>> +{ >>>>> + int ret = 0; >>>>> + struct iio_state *st = indio_dev->dev_data; >>>>> + struct iio_ring_buffer *ring; >>>>> + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); >>>>> + >>>>> + ring = iio_sw_rb_allocate(indio_dev); >>>>> + if (!ring) { >>>>> + ret = -ENOMEM; >>>>> + return ret; >>>>> + } >>>>> + indio_dev->ring = ring; >>>>> + >>>>> + iio_ring_sw_register_funcs(&ring->access); >>>>> + ring->preenable = &iio_common_ring_preenable; >>>>> + ring->postenable = &iio_common_ring_postenable; >>>>> + ring->predisable = &iio_common_ring_predisable; >>>>> + ring->owner = THIS_MODULE; >>>>> + >>>>> + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); >>>>> + if (indio_dev->pollfunc == NULL) { >>>>> + ret = -ENOMEM; >>>>> + goto error_iio_sw_rb_free;; >>>>> + } >>>>> + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; >>>>> + indio_dev->pollfunc->private_data = indio_dev; >>>>> + indio_dev->modes |= INDIO_RING_TRIGGERED; >>>>> + return 0; >>>>> + >>>>> +error_iio_sw_rb_free: >>>>> + iio_sw_rb_free(indio_dev->ring); >>>>> + return ret; >>>>> +} >>>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>>> + >>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>>> +{ >>>>> + kfree(indio_dev->pollfunc); >>>>> + iio_sw_rb_free(indio_dev->ring); >>>>> +} >>>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>>> + >>>> This next one is pointless except possibly to unify >>>> some naming so why do it? >>> Just a copy-paste and rename for existing code. Here we can let driver >>> call iio_ring_buffer_register/iio_ring_buffer_unregister directly? >> exactly. >>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>>> +{ >>>>> + return iio_ring_buffer_register(ring, 0); >>>>> +} >>>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>>> + >>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>>> +{ >>>>> + iio_ring_buffer_unregister(ring); >>>>> +} >>>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>>> + >>>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>>> + int index, >>>>> + s64 timestamp, >>>>> + int no_test) >>>>> +{ >>>>> + struct iio_state *st = iio_dev_get_devdata(dev_info); >>>>> + struct iio_trigger *trig = st->trig; >>>>> + >>>>> + trig->timestamp = timestamp; >>>>> + iio_trigger_poll(trig); >>>>> + >>>>> + return IRQ_HANDLED; >>>>> +} >>>>> + >>>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>>>> + >>>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>>> + >>>>> +static struct attribute *iio_trigger_attrs[] = { >>>>> + &dev_attr_name.attr, >>>>> + NULL, >>>>> +}; >>>>> + >>>>> +static const struct attribute_group iio_trigger_attr_group = { >>>>> + .attrs = iio_trigger_attrs, >>>>> +}; >>>>> + >>>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>>>> +{ >>>>> + struct iio_state *st = trig->private_data; >>>>> + enable_irq(st->irq); >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>>>> + bool state) >>>>> +{ >>>>> + struct iio_state *st = trig->private_data; >>>>> + struct iio_dev *indio_dev = st->indio_dev; >>>>> + int ret = 0; >>>>> + >>>>> + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >>>>> + ret = st->set_irq(st, state); >>>> This again is making some nasty assumptions. Yes some drivers >>>> use a shared event to supply dat ready events, others do not >>>> and if the line isn't shared they shouldn't as it adds a fair >>>> bit of complexity to this fast path. >>> you mean we should know the right interrupt line for data ready event >>> if there are more than one indio_dev->interrupts elemant? >> >> no. I meant that indio_dev->interrupts is meant to be NULL in those >> cases where the only interrupt (on a given line) is used for triggering. >> The situation >> used here is only meant to occur if the same line may indicate data >> ready or say a threshold interrupt and has to check which it is. >> If we only have a dataready signal this path adds considerably >> complexity for no reason. The reason I didn't comment on this in >> your drivers is that I assumed that event functionality was in the >> works. As it currently stands none of them should be using this >> method, they should all be using and handling the interrupt directly. >> The reason this complexity exists in the lis3l02dq is that it only >> has a single physical interrupt line an this is shared between data >> ready and theshold events. In my original adis16350 I dedicated >> one line to the alarms and one to the data ready. Obviously this >> is a bit restrictive on possible wiring so it may make sense to go >> the more complex route in software. >>> >>>>> + if (state == false) { >>>>> + iio_remove_event_from_list(&iio_event_common_trig, >>>>> + &indio_dev->interrupts[0] >>>>> + ->ev_list); >>>>> + flush_scheduled_work(); >>>>> + } else { >>>>> + iio_add_event_to_list(&iio_event_common_trig, >>>>> + &indio_dev->interrupts[0]->ev_list); >>>>> + } >>>>> + return ret; >>>>> +} >>>>> + >>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>>> +{ >>>>> + int ret; >>>>> + struct iio_state *st = indio_dev->dev_data; >>>>> + >>>>> + st->trig = iio_allocate_trigger(); >>>>> + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); >>>>> + if (!st->trig->name) { >>>>> + ret = -ENOMEM; >>>>> + goto error_free_trig; >>>>> + } >>>>> + snprintf((char *)st->trig->name, >>>>> + IIO_TRIGGER_NAME_LENGTH, >>>>> + "iio-dev%d", indio_dev->id); >>>>> + st->trig->dev.parent = st->parent_dev; >>>>> + st->trig->owner = THIS_MODULE; >>>>> + st->trig->private_data = st; >>>>> + st->trig->set_trigger_state = &iio_common_trigger_set_state; >>>>> + st->trig->try_reenable = &iio_common_trigger_try_reen; >>>>> + st->trig->control_attrs = &iio_trigger_attr_group; >>>>> + ret = iio_trigger_register(st->trig); >>>>> + >>>>> + /* select default trigger */ >>>>> + indio_dev->trig = st->trig; >>>>> + if (ret) >>>>> + goto error_free_trig_name; >>>>> + >>>>> + return 0; >>>>> + >>>>> +error_free_trig_name: >>>>> + kfree(st->trig->name); >>>>> +error_free_trig: >>>>> + iio_free_trigger(st->trig); >>>>> + >>>>> + return ret; >>>>> +} >>>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>>> + >>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>>> +{ >>>>> + struct iio_state *state = indio_dev->dev_data; >>>>> + >>>>> + iio_trigger_unregister(state->trig); >>>>> + kfree(state->trig->name); >>>>> + iio_free_trigger(state->trig); >>>>> +} >>>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>>>> Index: drivers/staging/iio/common-ring-trigger.h >>>>> =================================================================== >>>>> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>> @@ -0,0 +1,24 @@ >>>>> +/* The industrial I/O frequently used ring with trigger >>>>> + * >>>>> + * Copyright (c) 2010 Barry Song >>>>> + * >>>>> + * This program is free software; you can redistribute it and/or modify it >>>>> + * under the terms of the GNU General Public License version 2 as published by >>>>> + * the Free Software Foundation. >>>>> + * >>>>> + */ >>>>> + >>>>> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >>>>> +#define _IIO_COMMON_RING_TRIGGER_H_ >>>>> + >>>>> +#include "iio.h" >>>>> +#include "ring_generic.h" >>>>> + >>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev); >>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); >>>>> + >>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >>>>> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >>>>> Index: drivers/staging/iio/Kconfig >>>>> =================================================================== >>>>> --- drivers/staging/iio/Kconfig (revision 8893) >>>>> +++ drivers/staging/iio/Kconfig (working copy) >>>>> @@ -38,6 +38,12 @@ >>>>> ring buffers. The triggers are effectively a 'capture >>>>> data now' interrupt. >>>>> >>>>> +config IIO_COMMON_RING_TRIGGER >>>>> + boolean "Enable frequently used ring with trigger" >>>>> + depends on IIO_SW_RING && IIO_TRIGGER >>>>> + help >>>>> + Provides a generic ring with trigger. I can be used by most >>>>> + IIO devices. >>>>> >>>>> source "drivers/staging/iio/accel/Kconfig" >>>>> source "drivers/staging/iio/adc/Kconfig" >>>>> Index: drivers/staging/iio/Makefile >>>>> =================================================================== >>>>> --- drivers/staging/iio/Makefile (revision 8893) >>>>> +++ drivers/staging/iio/Makefile (working copy) >>>>> @@ -9,6 +9,8 @@ >>>>> >>>>> obj-$(CONFIG_IIO_SW_RING) += ring_sw.o >>>>> >>>>> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) += common-ring-trigger.o >>>>> + >>>>> obj-y += accel/ >>>>> obj-y += adc/ >>>>> obj-y += addac/ >>>>> >>>>> >>>>> >>>> >>>> >>>> >>> >> >> > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-12 17:35 ` Jonathan Cameron @ 2010-06-21 9:21 ` Barry Song 2010-06-25 14:11 ` Jonathan Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-21 9:21 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 Hi Jonathan, Thanks very much for your long description. But i am difficult to understand all those, so if there are pseudo codes, that will be much more helpful to me. I think you want to say 1. change iio_common_trigger_bh_to_ring into 3 step: get_data_from_hardware() fill_ring_buffer() notify_buffer_change() Yes. I completely agree because that will make it suitable for more cas= es. 2. remove work_cont struct since it is useless. 3.you want to say there is only one-copy for trigger , then another device will destory current device if using it as the trigger? IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); Here we can build one copy for every device. Thanks Barry On Sun, Jun 13, 2010 at 1:35 AM, Jonathan Cameron <jic23@cam.ac.uk> wro= te: > On 06/12/10 03:26, Barry Song wrote: > Hi Barry, > > I'm afraid I'm still on a useless net connection so don't have option > to review the code properly. > >> The driver doesn't aim to replace what has existed in iio core. Just >> improvement and a module which can be shared by most devices. Device= s >> which have special path can still self-define like before. > Indeed, this is a good idea. I'm just disagreeing with a few of the d= etails. > As things stand with this patch at the mo, its a take it or leave it > situation. I'd like to have it so drivers can cherry pick those eleme= nts > they want as that will give us the most advantages. >> >> On Fri, Jun 11, 2010 at 6:22 PM, Jonathan Cameron <jic23@cam.ac.uk> = wrote: >>> On 06/11/10 04:19, Barry Song wrote: >>>> On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk= > wrote: >>>>> On 06/10/10 05:48, Barry Song wrote: >>>>>> Just RFC for discussion. It is not the last patch To keep the ch= ange >>>>>> lest, i extract the common factor for most iio devices to a comm= on >>>>>> ring trigger module. Most devices can use the interfaces in this >>>>>> module directly. So copy-paste for ring and trigger is not neces= sary >>>>>> now. >>>>> Hi Barry, >>>>> >>>>> I'm afraid I'm not in a position to take a particularly >>>>> close look at this right now (on a rather slow net connection) >>>>> Thanks for taking a look at what we can unify. >>>>> >>>>> My immediate thought is that this patch may go a little too far, >>>>> certainly at this stage. =C2=A0It produces generic support for a >>>>> particular type of trigger (fine and useful) but I'm not >>>>> sure this should be grouped with the ring buffer setup elements. >>>>> There are plenty of devices that would benefit from parts of this >>>>> code, but currently it is all of the take it or leave it variety. >>>>> >>>>> In particular I'm not sure the ring buffer filling code should >>>>> be in here. =C2=A0It really isn't as consistent as the code impli= es >>>>> and by the presense of that element you have reduces the general >>>>> usefulness of rest. I'm very doubtful that we want to move things >>>>> like the rx and tx buffers out of the device drivers themselves. >>>>> The device drivers should control all access to the device, >>>>> not a core driver like this. >>>> Basically, rx and tx can be mo/ved into the priv of iio_state. Or >>>> iio_state can be moved into iio_dev? Then this structure is not >>>> needed? >>> They could but I still think these should be part of the locale >>> device driver state. I agree they don't need to be, but conceptualy >>> to my mind everything to do with actual communications with the chi= p >>> is not something the core (or helper modules like this one) should >>> touch. >> The bottom level hardware read/write can be part of the device drive= r. >> But the flow can be in the core. >> The iio_state is derived from objects like nand_chip, nand_base can >> handle data flow, the bottom_level nand driver just fill the last >> hardware access entries. > Exactly, but in there case they have a pretty good idea of what is co= ming > down the line. Here we don't, so i would prefer to see the separation= being > at the level of driver gets data and pushes to the core (in this case= the > buffer) rather than your proposal to insert another layer pulling fro= m the > driver and pushing to the core. I agree there looks to be a lot of sh= ared > code in various drivers and it is nice to get rid of it where possibl= e. > However this should be constrained by the need to maintain readabilit= y of > the code. In this particular case (just the buffer filling function n= ot the > rest which looks pretty good to me!) I think we loose clarity to save > few lines. =C2=A0My proposal is that, rather than passing your low le= vel > get data function to the handling code, just step up one level and pa= ss > the work struct (or related function) instead. =C2=A0Thus all device = related > manipulation remains in the device driver, and we still get the benef= it > of saving on a lot of replication. > > The principle issue here is that, even with your patch the core doesn= 't know > anywhere near enough about the incoming data from the chip. It curren= tly > has access to how many channels there are and whether there is a time= stamp. > To do the buffer fill it would need to know: > 1) Offsets in raw data coming off the chip (common case is to start a= ll reads > with a status byte - to get rid of this in your current code involve = an extra > copy of all data) > 2) The size of each element being read back. > 3) Packing of the data > > I can see your point that your current driver covers a number of devi= ces > that we already have drivers for. My issue is that with this one elem= ent > removed it covers pretty much any device with a dataready trigger. Th= at > seems like a bigger gain to me. > > If we divide things a little further, separating the ring buffer rela= ted > elements and the trigger related elements then some elements are usef= ul > to every driver with a software buffer. =C2=A0It is that gain that wo= uld be > most beneficial. >>>>> >>>>> Currently we don't have internal hooks to the contents >>>>> of the 'scans '. =C2=A0These could be added, but I think that wou= ld >>>>> add more complexity than simply allowing the drivers to handle >>>>> this aspect, not to mention adding some unecessary time penalty >>>>> to this path. >>>>> >>>>>> >>>>>> For iio core changes: >>>>>> 1. extract xxx_state to iio_state and add a private data to cont= ain >>>>>> chip-specific data >>>>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>>>> >>>>>> Index: drivers/staging/iio/iio.h >>>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>>> --- drivers/staging/iio/iio.h (revision 8893) >>>>>> +++ drivers/staging/iio/iio.h (working copy) >>>>>> @@ -447,4 +447,46 @@ >>>>>> >>>>>> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >>>>>> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >>>>>> + >>>>>> +/** >>>>>> + * struct iio_state - hardware level hooks for iio device >>>>>> + * @work_trigger_to_ring: bh for triggered event handling >>>>>> + * @work_cont_thresh: CLEAN >>>>>> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if = new interrupt has been triggered >>>>>> + * @last_timestamp: =C2=A0passing timestamp from th to bh of in= terrupt handler >>>>>> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= industrial I/O device structure >>>>>> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready t= rigger registered with iio >>>>>> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0transmit buffer >>>>>> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0recieve buffer >>>>>> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0mutex to protect tx and rx >>>>>> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= interrupt number >>>>>> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control t= he disable/enable of external interrupt >>>>>> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hard= ware by spi/i2c. >>>>>> + **/ >>>>>> +struct iio_state { >>>>>> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 *parent_dev >>>>>> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0work_trigger_to_ring; >>>>> > Whilst we are here, note the recent patch to remove work_cont structu= re. > We have nothing that currently needs it so it shouldn't be here. >>>>>> + =C2=A0 =C2=A0 struct iio_work_cont =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0work_cont_thresh; >>>>>> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >>>>>> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0*indio_dev; >>>>>> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0*trig; >>>>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >>>>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >>>>>> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; >>>>>> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >>>>>> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable= ); >>>>>> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx= ); >>>>>> + =C2=A0 =C2=A0 void *priv; >>>>>> +}; >>>>>> + >>>>>> +static inline void iio_state_set_privdata(struct iio_state *st,= void *data) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 st->priv =3D data; >>>>>> +} >>>>>> + >>>>>> +static inline void * iio_state_get_privdata(struct iio_state *s= t) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 return st->priv; >>>>>> +} >>>>>> + >>>>>> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >>>>>> Index: drivers/staging/iio/common-ring-trigger.c >>>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>>> @@ -0,0 +1,277 @@ >>>>>> +/* The software ring with trigger which can be used by most dri= vers >>>>>> + * >>>>>> + * Copyright (c) 2010 Barry Song >>>>>> + * >>>>>> + * This program is free software; you can redistribute it and/o= r modify it >>>>>> + * under the terms of the GNU General Public License version 2 = as published by >>>>>> + * the Free Software Foundation. >>>>>> + * >>>>>> + */ >>>>>> +#include <linux/kernel.h> >>>>>> +#include <linux/device.h> >>>>>> +#include <linux/interrupt.h> >>>>>> +#include <linux/fs.h> >>>>>> +#include <linux/poll.h> >>>>>> +#include <linux/module.h> >>>>>> +#include <linux/cdev.h> >>>>>> +#include <linux/slab.h> >>>>>> + >>>>>> +#include "iio.h" >>>>>> +#include "ring_generic.h" >>>>>> +#include "trigger.h" >>>>>> +#include "ring_sw.h" >>>>>> + >>>>>> +/* >>>>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>>>> + */ >>>>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 u16 _lower =3D lower; >>>>>> + =C2=A0 =C2=A0 u16 _upper =3D upper; >>>>>> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >>>>>> +} >>>>>> + >>>>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_= dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(ind= io_dev); >>>>>> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestam= p; >>>>>> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >>>>>> +} >>>>>> +/ >>>>> >>>>> This function is the one that mainly bothers me. =C2=A0We might >>>>> have a number of devices that do fit in here but there are >>>>> others that would use pretty much everything else but >>>>> this. =C2=A0I'd possibly be more inclined to leave this >>>>> to the drivers. =C2=A0That is where the knowledge about the >>>>> data layout in 'rx' comes from. >>>> >>>> Here we can let the hw_read_ring() do more, not only read hw, but = also >>>> fill the last data buffer, like combine_8_to_16(). >>> but once it is doing that much, what is te point of the following? >>> You will save a few repeated lines, but at the cost of driver >>> readability. I'm yet to be convinced that this function should exis= t. >>> Why not pass the appropriate work struct in having initialized it >>> in the chip driver? =C2=A0There are certainly elements of this code= that >>> will not be ideal for every device anyway (such as the kmalloc >>> being in here!) >> not just several saved lines. But mean the bottom level driver doesn= 't >> need to care the flow of trigger_bh_to_ring(). >> Bottom level driver doesn't need to self-define its >> trigger_bh_to_ring(), it only read hardware data and fill the data >> buffer. That's what the bottom level driver wants to do. > I agree that has a certain elegance, but unfortunately the bottom > level driver is still responsible for telling userspace what is > in the buffer. =C2=A0Thus I am yet to be convinced it shouldn't also > be responsible for filling the buffer. =C2=A0If we really want > to hide this from the device, then the following would work > > //Ask the driver for a suitably aligned pointer to the data > u8 *dat =3D iio_dev.get_data_for_buffer(u8 alignment); > ring.push_to_ring(dat); > iio_dev.notify_buffer_data_done(); > > Or (and this approach is needed if a device can use the buffer > elements directly for dma). > > u8 *data =3D ring.allocate_data(sizeofdata); > iio_dev.get_data_for_buffer(data); > ring.notify_filled(); > > Perhaps we should leave this element as one that need more > thought / debate and push on with the others. > > Also worth noting is that pretty much all these dataready > triggers will not currently work if 'only' another device > is using them as a trigger. (nothing clears the interrupt). > It may seem to be a fairly odd thing to do, and I'm still > wondering if it is better to insist this should work in > all drivers, or to actively prevent it. Both options are > non trivial. > > Looking more at the functions covered I'm not sure > that it wouldn't be better to just provide the useful > ones as 'library functions' that a driver can cherry > pick it they are applicable or in some cases make > the the default with the option to override deliberately > for cases they do not cover. > > >>>> >>>>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *w= ork_s) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *st >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(wor= k_s, struct iio_state, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >>>>>> + >>>>>> + =C2=A0 =C2=A0 int i =3D 0; >>>>>> + =C2=A0 =C2=A0 s16 *data; >>>>>> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_b= pd(st->indio_dev->ring); >>>>>> + >>>>>> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err= (st->parent_dev, "memory alloc failed in ring bh"); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >>>>>> + >>>>>> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring= (st, st->rx) >=3D 0) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 for (; i < st->indio_dev->scan_count; i++) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[= i*2+1], >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 st->rx[i*2]); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 } >>>>>> + >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 = byte boundary */ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 = *)(data + ((i + 3)/4)*4)) =3D st->last_timestamp; >>>>>> + >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_t= o(st->indio_dev->ring, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0(u8 *)data, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0st->last_timestamp); >>>>>> + >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_d= ev->trig); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >>>>>> + >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>>>> +} >>>>>> + >>>>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 size_t size; >>>>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>>>> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled,= if not fail*/ >>>>>> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_t= imestamp)) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >>>>>> + >>>>>> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_= timestamp) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 if (indio_dev->scan_count) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and d= ata */ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count *= sizeof(s16)) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 & ~(sizeof(s64) - 1)) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeo= f(s64); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 else /* Timestamp only =C2=A0*/ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 size =3D indio_dev->scan_count*sizeof(s16); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->acc= ess.set_bpd(indio_dev->ring, size); >>>>>> + =C2=A0 =C2=A0 } >>>>>> + >>>>>> + =C2=A0 =C2=A0 return 0; >>>>>> +} >>>>>> + >>>>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev= ) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_t= rigger_attach_poll_func(indio_dev->trig, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>>>> +} >>>>>> + >>>>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev= ) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_t= rigger_dettach_poll_func(indio_dev->trig, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>>>> +} >>>>>> + >>>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>>>> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >>>>>> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_= trigger_bh_to_ring); >>>>>> + >>>>>> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >>>>>> + =C2=A0 =C2=A0 if (!ring) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >>>>>> + =C2=A0 =C2=A0 } >>>>>> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >>>>>> + >>>>>> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); >>>>>> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; >>>>>> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable= ; >>>>>> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable= ; >>>>>> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >>>>>> + >>>>>> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_de= v->pollfunc), GFP_KERNEL); >>>>>> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb= _free;; >>>>>> + =C2=A0 =C2=A0 } >>>>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_com= mon_ring_poll_func_th; >>>>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >>>>>> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >>>>>> + =C2=A0 =C2=A0 return 0; >>>>>> + >>>>>> +error_iio_sw_rb_free: >>>>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>>>> + =C2=A0 =C2=A0 return ret; >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>>>> + >>>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >>>>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>>>> + >>>>> This next one is pointless except possibly to unify >>>>> some naming so why do it? >>>> Just a copy-paste and rename for existing code. Here we can let dr= iver >>>> call =C2=A0iio_ring_buffer_register/iio_ring_buffer_unregister dir= ectly? >>> exactly. >>>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>>>> + >>>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>>>> + >>>>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int inde= x, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 time= stamp, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_t= est) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev= _info); >>>>>> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >>>>>> + >>>>>> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >>>>>> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >>>>>> + >>>>>> + =C2=A0 =C2=A0 return IRQ_HANDLED; >>>>>> +} >>>>>> + >>>>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>>>>> + >>>>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>>>> + >>>>>> +static struct attribute *iio_trigger_attrs[] =3D { >>>>>> + =C2=A0 =C2=A0 &dev_attr_name.attr, >>>>>> + =C2=A0 =C2=A0 NULL, >>>>>> +}; >>>>>> + >>>>>> +static const struct attribute_group iio_trigger_attr_group =3D = { >>>>>> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >>>>>> +}; >>>>>> + >>>>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig= ) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>>>> + =C2=A0 =C2=A0 enable_irq(st->irq); >>>>>> + =C2=A0 =C2=A0 return 0; >>>>>> +} >>>>>> + >>>>>> +static int iio_common_trigger_set_state(struct iio_trigger *tri= g, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>>>> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >>>>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>>>> + >>>>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, = state); >>>>>> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); >>>>> This again is making some nasty assumptions. Yes some drivers >>>>> use a shared event to supply dat ready events, others do not >>>>> and if the line isn't shared they shouldn't as it adds a fair >>>>> bit of complexity to this fast path. >>>> you mean we should know the right interrupt line for data ready ev= ent >>>> if there are more than one indio_dev->interrupts elemant? >>> >>> no. I meant that indio_dev->interrupts is meant to be NULL in those >>> cases where the only interrupt (on a given line) is used for trigge= ring. >>> The situation >>> used here is only meant to occur if the same line may indicate data >>> ready or say a threshold interrupt and has to check which it is. >>> If we only have a dataready signal this path adds considerably >>> complexity for no reason. =C2=A0The reason I didn't comment on this= in >>> your drivers is that I assumed that event functionality was in the >>> works. =C2=A0As it currently stands none of them should be using th= is >>> method, they should all be using and handling the interrupt directl= y. >>> The reason this complexity exists in the lis3l02dq is that it only >>> has a single physical interrupt line an this is shared between data >>> ready and theshold events. =C2=A0In my original adis16350 I dedicat= ed >>> one line to the alarms and one to the data ready. =C2=A0Obviously t= his >>> is a bit restrictive on possible wiring so it may make sense to go >>> the more complex route in software. >>>> >>>>>> + =C2=A0 =C2=A0 if (state =3D=3D false) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_fro= m_list(&iio_event_common_trig, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work= (); >>>>>> + =C2=A0 =C2=A0 } else { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_lis= t(&iio_event_common_trig, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list)= ; >>>>>> + =C2=A0 =C2=A0 } >>>>>> + =C2=A0 =C2=A0 return ret; >>>>>> +} >>>>>> + >>>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 int ret; >>>>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>>>> + >>>>>> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >>>>>> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENG= TH, GFP_KERNEL); >>>>>> + =C2=A0 =C2=A0 if (!st->trig->name) { >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig= ; >>>>>> + =C2=A0 =C2=A0 } >>>>>> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 IIO_TRIGGER_NAME_LENGTH, >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 "iio-dev%d", indio_dev->id); >>>>>> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >>>>>> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >>>>>> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >>>>>> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trig= ger_set_state; >>>>>> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_t= ry_reen; >>>>>> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_gr= oup; >>>>>> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >>>>>> + >>>>>> + =C2=A0 =C2=A0 /* select default trigger */ >>>>>> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >>>>>> + =C2=A0 =C2=A0 if (ret) >>>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig= _name; >>>>>> + >>>>>> + =C2=A0 =C2=A0 return 0; >>>>>> + >>>>>> +error_free_trig_name: >>>>>> + =C2=A0 =C2=A0 kfree(st->trig->name); >>>>>> +error_free_trig: >>>>>> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >>>>>> + >>>>>> + =C2=A0 =C2=A0 return ret; >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>>>> + >>>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>>>> +{ >>>>>> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >>>>>> + >>>>>> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >>>>>> + =C2=A0 =C2=A0 kfree(state->trig->name); >>>>>> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >>>>>> +} >>>>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>>>>> Index: drivers/staging/iio/common-ring-trigger.h >>>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>>> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>>> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>>> @@ -0,0 +1,24 @@ >>>>>> +/* The industrial I/O frequently used ring with trigger >>>>>> + * >>>>>> + * Copyright (c) 2010 Barry Song >>>>>> + * >>>>>> + * This program is free software; you can redistribute it and/o= r modify it >>>>>> + * under the terms of the GNU General Public License version 2 = as published by >>>>>> + * the Free Software Foundation. >>>>>> + * >>>>>> + */ >>>>>> + >>>>>> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >>>>>> +#define _IIO_COMMON_RING_TRIGGER_H_ >>>>>> + >>>>>> +#include "iio.h" >>>>>> +#include "ring_generic.h" >>>>>> + >>>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev); >>>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >>>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >>>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring)= ; >>>>>> + >>>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >>>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >>>>>> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >>>>>> Index: drivers/staging/iio/Kconfig >>>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>>> --- drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (revision 8= 893) >>>>>> +++ drivers/staging/iio/Kconfig =C2=A0 =C2=A0 =C2=A0 (working co= py) >>>>>> @@ -38,6 +38,12 @@ >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ring buffers. =C2=A0The triggers are= effectively a 'capture >>>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 data now' interrupt. >>>>>> >>>>>> +config IIO_COMMON_RING_TRIGGER >>>>>> + =C2=A0 =C2=A0 boolean "Enable frequently used ring with trigge= r" >>>>>> + =C2=A0 =C2=A0 depends on IIO_SW_RING && IIO_TRIGGER >>>>>> + =C2=A0 =C2=A0 help >>>>>> + =C2=A0 =C2=A0 =C2=A0 Provides a generic ring with trigger. I c= an be used by most >>>>>> + =C2=A0 =C2=A0 =C2=A0 IIO devices. >>>>>> >>>>>> =C2=A0source "drivers/staging/iio/accel/Kconfig" >>>>>> =C2=A0source "drivers/staging/iio/adc/Kconfig" >>>>>> Index: drivers/staging/iio/Makefile >>>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>>> --- drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(revision 8= 893) >>>>>> +++ drivers/staging/iio/Makefile =C2=A0 =C2=A0 =C2=A0(working co= py) >>>>>> @@ -9,6 +9,8 @@ >>>>>> >>>>>> =C2=A0obj-$(CONFIG_IIO_SW_RING) +=3D ring_sw.o >>>>>> >>>>>> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) +=3D common-ring-trigger.= o >>>>>> + >>>>>> =C2=A0obj-y +=3D accel/ >>>>>> =C2=A0obj-y +=3D adc/ >>>>>> =C2=A0obj-y +=3D addac/ >>>>>> >>>>>> >>>>>> >>>>> >>>>> >>>>> >>>> >>> >>> >> > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-21 9:21 ` Barry Song @ 2010-06-25 14:11 ` Jonathan Cameron 0 siblings, 0 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-06-25 14:11 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/21/10 10:21, Barry Song wrote: > Hi Jonathan, Hi Barry, I think this conversation has gotten too involved. I for one have lost track of where we are. I propose splitting the original patch up into a number of subelements that we can discuss separately. I'll post a series that pulls out some of the completely uncontroversial bits asap. > Thanks very much for your long description. But i am difficult to > understand all those, so if there are pseudo codes, that will be much > more helpful to me. > I think you want to say > 1. change iio_common_trigger_bh_to_ring into 3 step: > get_data_from_hardware() > fill_ring_buffer() > notify_buffer_change() > Yes. I completely agree because that will make it suitable for more cases. I'm still far from convinced this is a good idea at all. The fundamental problem is that the patch moves some but not all of the ring handling into the core (or out of the driver at least!). This leaves a nasty disconnect between which bits of the code know about the ring buffer. If it all stays in the driver (with some clean ups lifted from your patch) then all of the device dependent elements of the ring buffer usage remain in the device driver. Yes we end up repeating some code, though not nearly as much as currently as a lot of your patch makes sense to me, just not this bit! I think this is a price we have to pay to not end up with a confusing and to my mind illogical structure to the drivers. Anyhow, lets see how much we differ after we have lifted the bits we agree on out of the patch into a nice incremental series. Jonathan > > 2. remove work_cont struct since it is useless. > > 3.you want to say there is only one-copy for trigger , then another > device will destory current device if using it as the trigger? > IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); > Here we can build one copy for every device. I have a lot of other issues with this bit of the code, so lets discuss that separately from the ring buffer setup elements. Jonathan > > Thanks > Barry > > On Sun, Jun 13, 2010 at 1:35 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> On 06/12/10 03:26, Barry Song wrote: >> Hi Barry, >> >> I'm afraid I'm still on a useless net connection so don't have option >> to review the code properly. >> >>> The driver doesn't aim to replace what has existed in iio core. Just >>> improvement and a module which can be shared by most devices. Devices >>> which have special path can still self-define like before. >> Indeed, this is a good idea. I'm just disagreeing with a few of the details. >> As things stand with this patch at the mo, its a take it or leave it >> situation. I'd like to have it so drivers can cherry pick those elements >> they want as that will give us the most advantages. >>> >>> On Fri, Jun 11, 2010 at 6:22 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >>>> On 06/11/10 04:19, Barry Song wrote: >>>>> On Thu, Jun 10, 2010 at 9:48 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >>>>>> On 06/10/10 05:48, Barry Song wrote: >>>>>>> Just RFC for discussion. It is not the last patch To keep the change >>>>>>> lest, i extract the common factor for most iio devices to a common >>>>>>> ring trigger module. Most devices can use the interfaces in this >>>>>>> module directly. So copy-paste for ring and trigger is not necessary >>>>>>> now. >>>>>> Hi Barry, >>>>>> >>>>>> I'm afraid I'm not in a position to take a particularly >>>>>> close look at this right now (on a rather slow net connection) >>>>>> Thanks for taking a look at what we can unify. >>>>>> >>>>>> My immediate thought is that this patch may go a little too far, >>>>>> certainly at this stage. It produces generic support for a >>>>>> particular type of trigger (fine and useful) but I'm not >>>>>> sure this should be grouped with the ring buffer setup elements. >>>>>> There are plenty of devices that would benefit from parts of this >>>>>> code, but currently it is all of the take it or leave it variety. >>>>>> >>>>>> In particular I'm not sure the ring buffer filling code should >>>>>> be in here. It really isn't as consistent as the code implies >>>>>> and by the presense of that element you have reduces the general >>>>>> usefulness of rest. I'm very doubtful that we want to move things >>>>>> like the rx and tx buffers out of the device drivers themselves. >>>>>> The device drivers should control all access to the device, >>>>>> not a core driver like this. >>>>> Basically, rx and tx can be mo/ved into the priv of iio_state. Or >>>>> iio_state can be moved into iio_dev? Then this structure is not >>>>> needed? >>>> They could but I still think these should be part of the locale >>>> device driver state. I agree they don't need to be, but conceptualy >>>> to my mind everything to do with actual communications with the chip >>>> is not something the core (or helper modules like this one) should >>>> touch. >>> The bottom level hardware read/write can be part of the device driver. >>> But the flow can be in the core. >>> The iio_state is derived from objects like nand_chip, nand_base can >>> handle data flow, the bottom_level nand driver just fill the last >>> hardware access entries. >> Exactly, but in there case they have a pretty good idea of what is coming >> down the line. Here we don't, so i would prefer to see the separation being >> at the level of driver gets data and pushes to the core (in this case the >> buffer) rather than your proposal to insert another layer pulling from the >> driver and pushing to the core. I agree there looks to be a lot of shared >> code in various drivers and it is nice to get rid of it where possible. >> However this should be constrained by the need to maintain readability of >> the code. In this particular case (just the buffer filling function not the >> rest which looks pretty good to me!) I think we loose clarity to save >> few lines. My proposal is that, rather than passing your low level >> get data function to the handling code, just step up one level and pass >> the work struct (or related function) instead. Thus all device related >> manipulation remains in the device driver, and we still get the benefit >> of saving on a lot of replication. >> >> The principle issue here is that, even with your patch the core doesn't know >> anywhere near enough about the incoming data from the chip. It currently >> has access to how many channels there are and whether there is a timestamp. >> To do the buffer fill it would need to know: >> 1) Offsets in raw data coming off the chip (common case is to start all reads >> with a status byte - to get rid of this in your current code involve an extra >> copy of all data) >> 2) The size of each element being read back. >> 3) Packing of the data >> >> I can see your point that your current driver covers a number of devices >> that we already have drivers for. My issue is that with this one element >> removed it covers pretty much any device with a dataready trigger. That >> seems like a bigger gain to me. >> >> If we divide things a little further, separating the ring buffer related >> elements and the trigger related elements then some elements are useful >> to every driver with a software buffer. It is that gain that would be >> most beneficial. >>>>>> >>>>>> Currently we don't have internal hooks to the contents >>>>>> of the 'scans '. These could be added, but I think that would >>>>>> add more complexity than simply allowing the drivers to handle >>>>>> this aspect, not to mention adding some unecessary time penalty >>>>>> to this path. >>>>>> >>>>>>> >>>>>>> For iio core changes: >>>>>>> 1. extract xxx_state to iio_state and add a private data to contain >>>>>>> chip-specific data >>>>>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>>>>> >>>>>>> Index: drivers/staging/iio/iio.h >>>>>>> =================================================================== >>>>>>> --- drivers/staging/iio/iio.h (revision 8893) >>>>>>> +++ drivers/staging/iio/iio.h (working copy) >>>>>>> @@ -447,4 +447,46 @@ >>>>>>> >>>>>>> int iio_get_new_idr_val(struct idr *this_idr); >>>>>>> void iio_free_idr_val(struct idr *this_idr, int id); >>>>>>> + >>>>>>> +/** >>>>>>> + * struct iio_state - hardware level hooks for iio device >>>>>>> + * @work_trigger_to_ring: bh for triggered event handling >>>>>>> + * @work_cont_thresh: CLEAN >>>>>>> + * @inter: used to check if new interrupt has been triggered >>>>>>> + * @last_timestamp: passing timestamp from th to bh of interrupt handler >>>>>>> + * @indio_dev: industrial I/O device structure >>>>>>> + * @trig: data ready trigger registered with iio >>>>>>> + * @tx: transmit buffer >>>>>>> + * @rx: recieve buffer >>>>>>> + * @buf_lock: mutex to protect tx and rx >>>>>>> + * @irq: interrupt number >>>>>>> + * @set_irq: control the disable/enable of external interrupt >>>>>>> + * @hw_read_ring: read ring data from hardware by spi/i2c. >>>>>>> + **/ >>>>>>> +struct iio_state { >>>>>>> + struct device *parent_dev >>>>>>> + struct work_struct work_trigger_to_ring; >>>>>> >> Whilst we are here, note the recent patch to remove work_cont structure. >> We have nothing that currently needs it so it shouldn't be here. >>>>>>> + struct iio_work_cont work_cont_thresh; >>>>>>> + s64 last_timestamp; >>>>>>> + struct iio_dev *indio_dev; >>>>>>> + struct iio_trigger *trig; >>>>>>> + u8 *tx; >>>>>>> + u8 *rx; >>>>>>> + struct mutex buf_lock; >>>>>>> + int irq; >>>>>>> + int (*set_irq)(struct iio_state *st, bool enable); >>>>>>> + int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>>>>>> + void *priv; >>>>>>> +}; >>>>>>> + >>>>>>> +static inline void iio_state_set_privdata(struct iio_state *st, void *data) >>>>>>> +{ >>>>>>> + st->priv = data; >>>>>>> +} >>>>>>> + >>>>>>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>>>>>> +{ >>>>>>> + return st->priv; >>>>>>> +} >>>>>>> + >>>>>>> #endif /* _INDUSTRIAL_IO_H_ */ >>>>>>> Index: drivers/staging/iio/common-ring-trigger.c >>>>>>> =================================================================== >>>>>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>>>>> @@ -0,0 +1,277 @@ >>>>>>> +/* The software ring with trigger which can be used by most drivers >>>>>>> + * >>>>>>> + * Copyright (c) 2010 Barry Song >>>>>>> + * >>>>>>> + * This program is free software; you can redistribute it and/or modify it >>>>>>> + * under the terms of the GNU General Public License version 2 as published by >>>>>>> + * the Free Software Foundation. >>>>>>> + * >>>>>>> + */ >>>>>>> +#include <linux/kernel.h> >>>>>>> +#include <linux/device.h> >>>>>>> +#include <linux/interrupt.h> >>>>>>> +#include <linux/fs.h> >>>>>>> +#include <linux/poll.h> >>>>>>> +#include <linux/module.h> >>>>>>> +#include <linux/cdev.h> >>>>>>> +#include <linux/slab.h> >>>>>>> + >>>>>>> +#include "iio.h" >>>>>>> +#include "ring_generic.h" >>>>>>> +#include "trigger.h" >>>>>>> +#include "ring_sw.h" >>>>>>> + >>>>>>> +/* >>>>>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>>>>> + */ >>>>>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>>>>> +{ >>>>>>> + u16 _lower = lower; >>>>>>> + u16 _upper = upper; >>>>>>> + return _lower | (_upper << 8); >>>>>>> +} >>>>>>> + >>>>>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + struct iio_state *st = iio_dev_get_devdata(indio_dev); >>>>>>> + st->last_timestamp = indio_dev->trig->timestamp; >>>>>>> + schedule_work(&st->work_trigger_to_ring); >>>>>>> +} >>>>>>> +/ >>>>>> >>>>>> This function is the one that mainly bothers me. We might >>>>>> have a number of devices that do fit in here but there are >>>>>> others that would use pretty much everything else but >>>>>> this. I'd possibly be more inclined to leave this >>>>>> to the drivers. That is where the knowledge about the >>>>>> data layout in 'rx' comes from. >>>>> >>>>> Here we can let the hw_read_ring() do more, not only read hw, but also >>>>> fill the last data buffer, like combine_8_to_16(). >>>> but once it is doing that much, what is te point of the following? >>>> You will save a few repeated lines, but at the cost of driver >>>> readability. I'm yet to be convinced that this function should exist. >>>> Why not pass the appropriate work struct in having initialized it >>>> in the chip driver? There are certainly elements of this code that >>>> will not be ideal for every device anyway (such as the kmalloc >>>> being in here!) >>> not just several saved lines. But mean the bottom level driver doesn't >>> need to care the flow of trigger_bh_to_ring(). >>> Bottom level driver doesn't need to self-define its >>> trigger_bh_to_ring(), it only read hardware data and fill the data >>> buffer. That's what the bottom level driver wants to do. >> I agree that has a certain elegance, but unfortunately the bottom >> level driver is still responsible for telling userspace what is >> in the buffer. Thus I am yet to be convinced it shouldn't also >> be responsible for filling the buffer. If we really want >> to hide this from the device, then the following would work >> >> //Ask the driver for a suitably aligned pointer to the data >> u8 *dat = iio_dev.get_data_for_buffer(u8 alignment); >> ring.push_to_ring(dat); >> iio_dev.notify_buffer_data_done(); >> >> Or (and this approach is needed if a device can use the buffer >> elements directly for dma). >> >> u8 *data = ring.allocate_data(sizeofdata); >> iio_dev.get_data_for_buffer(data); >> ring.notify_filled(); >> >> Perhaps we should leave this element as one that need more >> thought / debate and push on with the others. >> >> Also worth noting is that pretty much all these dataready >> triggers will not currently work if 'only' another device >> is using them as a trigger. (nothing clears the interrupt). >> It may seem to be a fairly odd thing to do, and I'm still >> wondering if it is better to insist this should work in >> all drivers, or to actively prevent it. Both options are >> non trivial. >> >> Looking more at the functions covered I'm not sure >> that it wouldn't be better to just provide the useful >> ones as 'library functions' that a driver can cherry >> pick it they are applicable or in some cases make >> the the default with the option to override deliberately >> for cases they do not cover. >> >> >>>>> >>>>>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>>>>>> +{ >>>>>>> + struct iio_state *st >>>>>>> + = container_of(work_s, struct iio_state, >>>>>>> + work_trigger_to_ring); >>>>>>> + >>>>>>> + int i = 0; >>>>>>> + s16 *data; >>>>>>> + size_t datasize = st->indio_dev >>>>>>> + ->ring->access.get_bpd(st->indio_dev->ring); >>>>>>> + >>>>>>> + data = kmalloc(datasize , GFP_KERNEL); >>>>>>> + if (data == NULL) { >>>>>>> + dev_err(st->parent_dev, "memory alloc failed in ring bh"); >>>>>>> + return; >>>>>>> + } >>>>>>> + >>>>>>> + if (st->indio_dev->scan_count) >>>>>>> + if (st->hw_read_ring(st, st->rx) >= 0) >>>>>>> + for (; i < st->indio_dev->scan_count; i++) { >>>>>>> + data[i] = combine_8_to_16(st->rx[i*2+1], >>>>>>> + st->rx[i*2]); >>>>>>> + } >>>>>>> + >>>>>>> + /* Guaranteed to be aligned with 8 byte boundary */ >>>>>>> + if (st->indio_dev->scan_timestamp) >>>>>>> + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; >>>>>>> + >>>>>>> + st->indio_dev->ring->access.store_to(st->indio_dev->ring, >>>>>>> + (u8 *)data, >>>>>>> + st->last_timestamp); >>>>>>> + >>>>>>> + iio_trigger_notify_done(st->indio_dev->trig); >>>>>>> + kfree(data); >>>>>>> + >>>>>>> + return; >>>>>>> +} >>>>>>> + >>>>>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + size_t size; >>>>>>> + dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>>>>> + /* Check if there are any scan elements enabled, if not fail*/ >>>>>>> + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) >>>>>>> + return -EINVAL; >>>>>>> + >>>>>>> + if (indio_dev->ring->access.set_bpd) { >>>>>>> + if (indio_dev->scan_timestamp) >>>>>>> + if (indio_dev->scan_count) >>>>>>> + /* Timestamp (aligned to s64) and data */ >>>>>>> + size = (((indio_dev->scan_count * sizeof(s16)) >>>>>>> + + sizeof(s64) - 1) >>>>>>> + & ~(sizeof(s64) - 1)) >>>>>>> + + sizeof(s64); >>>>>>> + else /* Timestamp only */ >>>>>>> + size = sizeof(s64); >>>>>>> + else /* Data only */ >>>>>>> + size = indio_dev->scan_count*sizeof(s16); >>>>>>> + indio_dev->ring->access.set_bpd(indio_dev->ring, size); >>>>>>> + } >>>>>>> + >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + return indio_dev->trig >>>>>>> + ? iio_trigger_attach_poll_func(indio_dev->trig, >>>>>>> + indio_dev->pollfunc) >>>>>>> + : 0; >>>>>>> +} >>>>>>> + >>>>>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + return indio_dev->trig >>>>>>> + ? iio_trigger_dettach_poll_func(indio_dev->trig, >>>>>>> + indio_dev->pollfunc) >>>>>>> + : 0; >>>>>>> +} >>>>>>> + >>>>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + int ret = 0; >>>>>>> + struct iio_state *st = indio_dev->dev_data; >>>>>>> + struct iio_ring_buffer *ring; >>>>>>> + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); >>>>>>> + >>>>>>> + ring = iio_sw_rb_allocate(indio_dev); >>>>>>> + if (!ring) { >>>>>>> + ret = -ENOMEM; >>>>>>> + return ret; >>>>>>> + } >>>>>>> + indio_dev->ring = ring; >>>>>>> + >>>>>>> + iio_ring_sw_register_funcs(&ring->access); >>>>>>> + ring->preenable = &iio_common_ring_preenable; >>>>>>> + ring->postenable = &iio_common_ring_postenable; >>>>>>> + ring->predisable = &iio_common_ring_predisable; >>>>>>> + ring->owner = THIS_MODULE; >>>>>>> + >>>>>>> + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); >>>>>>> + if (indio_dev->pollfunc == NULL) { >>>>>>> + ret = -ENOMEM; >>>>>>> + goto error_iio_sw_rb_free;; >>>>>>> + } >>>>>>> + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; >>>>>>> + indio_dev->pollfunc->private_data = indio_dev; >>>>>>> + indio_dev->modes |= INDIO_RING_TRIGGERED; >>>>>>> + return 0; >>>>>>> + >>>>>>> +error_iio_sw_rb_free: >>>>>>> + iio_sw_rb_free(indio_dev->ring); >>>>>>> + return ret; >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>>>>> + >>>>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + kfree(indio_dev->pollfunc); >>>>>>> + iio_sw_rb_free(indio_dev->ring); >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>>>>> + >>>>>> This next one is pointless except possibly to unify >>>>>> some naming so why do it? >>>>> Just a copy-paste and rename for existing code. Here we can let driver >>>>> call iio_ring_buffer_register/iio_ring_buffer_unregister directly? >>>> exactly. >>>>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>>>>> +{ >>>>>>> + return iio_ring_buffer_register(ring, 0); >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>>>>> + >>>>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>>>>> +{ >>>>>>> + iio_ring_buffer_unregister(ring); >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>>>>> + >>>>>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>>>>> + int index, >>>>>>> + s64 timestamp, >>>>>>> + int no_test) >>>>>>> +{ >>>>>>> + struct iio_state *st = iio_dev_get_devdata(dev_info); >>>>>>> + struct iio_trigger *trig = st->trig; >>>>>>> + >>>>>>> + trig->timestamp = timestamp; >>>>>>> + iio_trigger_poll(trig); >>>>>>> + >>>>>>> + return IRQ_HANDLED; >>>>>>> +} >>>>>>> + >>>>>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>>>>>> + >>>>>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>>>>> + >>>>>>> +static struct attribute *iio_trigger_attrs[] = { >>>>>>> + &dev_attr_name.attr, >>>>>>> + NULL, >>>>>>> +}; >>>>>>> + >>>>>>> +static const struct attribute_group iio_trigger_attr_group = { >>>>>>> + .attrs = iio_trigger_attrs, >>>>>>> +}; >>>>>>> + >>>>>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>>>>>> +{ >>>>>>> + struct iio_state *st = trig->private_data; >>>>>>> + enable_irq(st->irq); >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>>>>>> + bool state) >>>>>>> +{ >>>>>>> + struct iio_state *st = trig->private_data; >>>>>>> + struct iio_dev *indio_dev = st->indio_dev; >>>>>>> + int ret = 0; >>>>>>> + >>>>>>> + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >>>>>>> + ret = st->set_irq(st, state); >>>>>> This again is making some nasty assumptions. Yes some drivers >>>>>> use a shared event to supply dat ready events, others do not >>>>>> and if the line isn't shared they shouldn't as it adds a fair >>>>>> bit of complexity to this fast path. >>>>> you mean we should know the right interrupt line for data ready event >>>>> if there are more than one indio_dev->interrupts elemant? >>>> >>>> no. I meant that indio_dev->interrupts is meant to be NULL in those >>>> cases where the only interrupt (on a given line) is used for triggering. >>>> The situation >>>> used here is only meant to occur if the same line may indicate data >>>> ready or say a threshold interrupt and has to check which it is. >>>> If we only have a dataready signal this path adds considerably >>>> complexity for no reason. The reason I didn't comment on this in >>>> your drivers is that I assumed that event functionality was in the >>>> works. As it currently stands none of them should be using this >>>> method, they should all be using and handling the interrupt directly. >>>> The reason this complexity exists in the lis3l02dq is that it only >>>> has a single physical interrupt line an this is shared between data >>>> ready and theshold events. In my original adis16350 I dedicated >>>> one line to the alarms and one to the data ready. Obviously this >>>> is a bit restrictive on possible wiring so it may make sense to go >>>> the more complex route in software. >>>>> >>>>>>> + if (state == false) { >>>>>>> + iio_remove_event_from_list(&iio_event_common_trig, >>>>>>> + &indio_dev->interrupts[0] >>>>>>> + ->ev_list); >>>>>>> + flush_scheduled_work(); >>>>>>> + } else { >>>>>>> + iio_add_event_to_list(&iio_event_common_trig, >>>>>>> + &indio_dev->interrupts[0]->ev_list); >>>>>>> + } >>>>>>> + return ret; >>>>>>> +} >>>>>>> + >>>>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + int ret; >>>>>>> + struct iio_state *st = indio_dev->dev_data; >>>>>>> + >>>>>>> + st->trig = iio_allocate_trigger(); >>>>>>> + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); >>>>>>> + if (!st->trig->name) { >>>>>>> + ret = -ENOMEM; >>>>>>> + goto error_free_trig; >>>>>>> + } >>>>>>> + snprintf((char *)st->trig->name, >>>>>>> + IIO_TRIGGER_NAME_LENGTH, >>>>>>> + "iio-dev%d", indio_dev->id); >>>>>>> + st->trig->dev.parent = st->parent_dev; >>>>>>> + st->trig->owner = THIS_MODULE; >>>>>>> + st->trig->private_data = st; >>>>>>> + st->trig->set_trigger_state = &iio_common_trigger_set_state; >>>>>>> + st->trig->try_reenable = &iio_common_trigger_try_reen; >>>>>>> + st->trig->control_attrs = &iio_trigger_attr_group; >>>>>>> + ret = iio_trigger_register(st->trig); >>>>>>> + >>>>>>> + /* select default trigger */ >>>>>>> + indio_dev->trig = st->trig; >>>>>>> + if (ret) >>>>>>> + goto error_free_trig_name; >>>>>>> + >>>>>>> + return 0; >>>>>>> + >>>>>>> +error_free_trig_name: >>>>>>> + kfree(st->trig->name); >>>>>>> +error_free_trig: >>>>>>> + iio_free_trigger(st->trig); >>>>>>> + >>>>>>> + return ret; >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>>>>> + >>>>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>>>>> +{ >>>>>>> + struct iio_state *state = indio_dev->dev_data; >>>>>>> + >>>>>>> + iio_trigger_unregister(state->trig); >>>>>>> + kfree(state->trig->name); >>>>>>> + iio_free_trigger(state->trig); >>>>>>> +} >>>>>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>>>>>> Index: drivers/staging/iio/common-ring-trigger.h >>>>>>> =================================================================== >>>>>>> --- drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>>>> +++ drivers/staging/iio/common-ring-trigger.h (revision 0) >>>>>>> @@ -0,0 +1,24 @@ >>>>>>> +/* The industrial I/O frequently used ring with trigger >>>>>>> + * >>>>>>> + * Copyright (c) 2010 Barry Song >>>>>>> + * >>>>>>> + * This program is free software; you can redistribute it and/or modify it >>>>>>> + * under the terms of the GNU General Public License version 2 as published by >>>>>>> + * the Free Software Foundation. >>>>>>> + * >>>>>>> + */ >>>>>>> + >>>>>>> +#ifndef _IIO_COMMON_RING_TRIGGER_H_ >>>>>>> +#define _IIO_COMMON_RING_TRIGGER_H_ >>>>>>> + >>>>>>> +#include "iio.h" >>>>>>> +#include "ring_generic.h" >>>>>>> + >>>>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev); >>>>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev); >>>>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring); >>>>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring); >>>>>>> + >>>>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev); >>>>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev); >>>>>>> +#endif /* _IIO_COMMON_RING_TRIGGER_H_ */ >>>>>>> Index: drivers/staging/iio/Kconfig >>>>>>> =================================================================== >>>>>>> --- drivers/staging/iio/Kconfig (revision 8893) >>>>>>> +++ drivers/staging/iio/Kconfig (working copy) >>>>>>> @@ -38,6 +38,12 @@ >>>>>>> ring buffers. The triggers are effectively a 'capture >>>>>>> data now' interrupt. >>>>>>> >>>>>>> +config IIO_COMMON_RING_TRIGGER >>>>>>> + boolean "Enable frequently used ring with trigger" >>>>>>> + depends on IIO_SW_RING && IIO_TRIGGER >>>>>>> + help >>>>>>> + Provides a generic ring with trigger. I can be used by most >>>>>>> + IIO devices. >>>>>>> >>>>>>> source "drivers/staging/iio/accel/Kconfig" >>>>>>> source "drivers/staging/iio/adc/Kconfig" >>>>>>> Index: drivers/staging/iio/Makefile >>>>>>> =================================================================== >>>>>>> --- drivers/staging/iio/Makefile (revision 8893) >>>>>>> +++ drivers/staging/iio/Makefile (working copy) >>>>>>> @@ -9,6 +9,8 @@ >>>>>>> >>>>>>> obj-$(CONFIG_IIO_SW_RING) += ring_sw.o >>>>>>> >>>>>>> +obj-$(CONFIG_IIO_COMMON_RING_TRIGGER) += common-ring-trigger.o >>>>>>> + >>>>>>> obj-y += accel/ >>>>>>> obj-y += adc/ >>>>>>> obj-y += addac/ >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>>> >>>>>> >>>>> >>>> >>>> >>> >> >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-10 4:48 ` Barry Song 2010-06-10 4:51 ` Barry Song 2010-06-10 13:48 ` Jonathan Cameron @ 2010-06-25 17:18 ` Jonathan Cameron 2010-06-28 7:59 ` Barry Song 2 siblings, 1 reply; 31+ messages in thread From: Jonathan Cameron @ 2010-06-25 17:18 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 Hi Barry, I've dropped back to the original patch for a close analysis of what is going on. Sorry for the delay in getting to this! > Just RFC for discussion. It is not the last patch To keep the change > lest, i extract the common factor for most iio devices to a common > ring trigger module. Most devices can use the interfaces in this > module directly. So copy-paste for ring and trigger is not necessary > now. This time I'm going to concentrate of specific issues. Note I'm reading the code as being directed at the vast majority of cases. What you do here fairly radically changes the job of the device driver. What I don't want to do is end up with cases where a tiny difference in hardware results in two completely different approaches being needed to write the driver. In a fairly illogical process I wrote this from the bottom :) > > For iio core changes: > 1. extract xxx_state to iio_state and add a private data to contain > chip-specific data > 2. extract all xxx_ring/xxx_trigger api to common api > > Index: drivers/staging/iio/iio.h > =================================================================== > --- drivers/staging/iio/iio.h (revision 8893) > +++ drivers/staging/iio/iio.h (working copy) > @@ -447,4 +447,46 @@ > > int iio_get_new_idr_val(struct idr *this_idr); > void iio_free_idr_val(struct idr *this_idr, int id); > + > +/** > + * struct iio_state - hardware level hooks for iio device > + * @work_trigger_to_ring: bh for triggered event handling > + * @inter: used to check if new interrupt has been triggered > + * @last_timestamp: passing timestamp from th to bh of interrupt handler > + * @indio_dev: industrial I/O device structure > + * @trig: data ready trigger registered with iio > + * @tx: transmit buffer > + * @rx: recieve buffer > + * @buf_lock: mutex to protect tx and rx > + * @irq: interrupt number > + * @set_irq: control the disable/enable of external interrupt > + * @hw_read_ring: read ring data from hardware by spi/i2c. > + **/ > +struct iio_state { > + struct device *parent_dev; > + struct work_struct work_trigger_to_ring; > + s64 last_timestamp; > + struct iio_dev *indio_dev; > + struct iio_trigger *trig; Not all drivers will want shared centralized buffers. Simple devices might use the various spi and i2c functions that allocate data storage as needed within the functions. > + u8 *tx; > + u8 *rx; > + struct mutex buf_lock; Assumes single irq (lot of adis devices can have several) and makes a copy of it to get round deliberate hiding of bus info. > + int irq; > + int (*set_irq)(struct iio_state *st, bool enable); My issues with this are given where it is used. > + int (*hw_read_ring)(struct iio_state *st, u8 *rx); (as uncommented above) This is used to hide the bus specific info. > + void *priv; > +}; > + > +static inline void iio_state_set_privdata(struct iio_state *st, void *data) > +{ > + st->priv = data; > +} > + > +static inline void * iio_state_get_privdata(struct iio_state *st) > +{ > + return st->priv; > +} > + > #endif /* _INDUSTRIAL_IO_H_ */ > Index: drivers/staging/iio/common-ring-trigger.c > =================================================================== > --- drivers/staging/iio/common-ring-trigger.c (revision 0) > +++ drivers/staging/iio/common-ring-trigger.c (revision 0) > @@ -0,0 +1,277 @@ > +/* The software ring with trigger which can be used by most drivers > + * > + * Copyright (c) 2010 Barry Song > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + */ > +#include <linux/kernel.h> > +#include <linux/device.h> > +#include <linux/interrupt.h> > +#include <linux/fs.h> > +#include <linux/poll.h> > +#include <linux/module.h> > +#include <linux/cdev.h> > +#include <linux/slab.h> > + > +#include "iio.h" > +#include "ring_generic.h" > +#include "trigger.h" > +#include "ring_sw.h" > + > +/* > + * combine_8_to_16(): utility function to munge to u8s into u16 > + */ > +static inline u16 combine_8_to_16(u8 lower, u8 upper) > +{ > + u16 _lower = lower; > + u16 _upper = upper; > + return _lower | (_upper << 8); > +} > + > +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) > +{ > + struct iio_state *st = iio_dev_get_devdata(indio_dev); > + st->last_timestamp = indio_dev->trig->timestamp; > + schedule_work(&st->work_trigger_to_ring); > +} > + We discussed various options for this, but I'm personally yet to be convinced that we aren't making the driver code much harder to follow for the sake of saving lines of code. I'm also not sure that the approach currently used here is the right way to do it in any driver which doesn't help. One thing I would like to do is to loose the additional data copy required by the current approach of building a local record by copying form the raw data, then copying this record into the buffer. Preallocating space is easy enough with kfifo so I will probably do a rework of those patches shortly. For my sw_ring buffer I'm not sure if it can be easily done, but I'll look into it. > +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) > +{ > + struct iio_state *st > + = container_of(work_s, struct iio_state, > + work_trigger_to_ring); > + > + int i = 0; > + s16 *data; > + size_t datasize = st->indio_dev > + ->ring->access.get_bpd(st->indio_dev->ring); > + > + data = kmalloc(datasize , GFP_KERNEL); > + if (data == NULL) { > + dev_err(st->parent_dev, "memory alloc failed in ring bh"); > + return; > + } > + > + if (st->indio_dev->scan_count) > + if (st->hw_read_ring(st, st->rx) >= 0) > + for (; i < st->indio_dev->scan_count; i++) { > + data[i] = combine_8_to_16(st->rx[i*2+1], > + st->rx[i*2]); > + } > + > + /* Guaranteed to be aligned with 8 byte boundary */ > + if (st->indio_dev->scan_timestamp) > + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; > + > + st->indio_dev->ring->access.store_to(st->indio_dev->ring, > + (u8 *)data, > + st->last_timestamp); > + > + iio_trigger_notify_done(st->indio_dev->trig); > + kfree(data); > + > + return; > +} > + This one is pretty specific, though only in the central section working out the size. Can we come up with an easy way to share the rest of the code? The previous discussion including some possible solutions. I'm yet to be convinced that there is a clean way to do the equivalent of this given the large amount of knowledge your shared code would have to have about the underlying data. > +static int iio_common_ring_preenable(struct iio_dev *indio_dev) > +{ > + size_t size; > + dev_dbg(&indio_dev->dev, "%s\n", __func__); > + /* Check if there are any scan elements enabled, if not fail*/ > + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) > + return -EINVAL; > + > + if (indio_dev->ring->access.set_bpd) { > + if (indio_dev->scan_timestamp) > + if (indio_dev->scan_count) > + /* Timestamp (aligned to s64) and data */ > + size = (((indio_dev->scan_count * sizeof(s16)) > + + sizeof(s64) - 1) > + & ~(sizeof(s64) - 1)) > + + sizeof(s64); > + else /* Timestamp only */ > + size = sizeof(s64); > + else /* Data only */ > + size = indio_dev->scan_count*sizeof(s16); > + indio_dev->ring->access.set_bpd(indio_dev->ring, size); > + } > + > + return 0; > +} > + Agree entirely with the next two. Have moved to industrialio-trigger in todays first patch set. They apply in all current cases and for that matter in any I have yet thought up. > +static int iio_common_ring_postenable(struct iio_dev *indio_dev) > +{ > + return indio_dev->trig > + ? iio_trigger_attach_poll_func(indio_dev->trig, > + indio_dev->pollfunc) > + : 0; > +} > + > +static int iio_common_ring_predisable(struct iio_dev *indio_dev) > +{ > + return indio_dev->trig > + ? iio_trigger_dettach_poll_func(indio_dev->trig, > + indio_dev->pollfunc) > + : 0; > +} > + > +int iio_configure_common_ring(struct iio_dev *indio_dev) > +{ > + int ret = 0; > + struct iio_state *st = indio_dev->dev_data; > + struct iio_ring_buffer *ring; > + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); > + One reason I'm not keen on this as is, is that it means that all drivers using this code have to use the same buffer implementation. I'm very keen to make this selectable on a per driver basis. Obviously we could add hooks to make that work, but then we begin to destroy the point of your patch. > + ring = iio_sw_rb_allocate(indio_dev); > + if (!ring) { > + ret = -ENOMEM; > + return ret; > + } > + indio_dev->ring = ring; > + > + iio_ring_sw_register_funcs(&ring->access); As discussed above. This one is actually a bit of a pain. > + ring->preenable = &iio_common_ring_preenable; These last two are the same for all triggered software ring buffers, so I've moved the code into industrialio-trigger.c for now. > + ring->postenable = &iio_common_ring_postenable; > + ring->predisable = &iio_common_ring_predisable; > + ring->owner = THIS_MODULE; > + This makes it clear that it is sensible to have an alloc_pollfunc function as the next 8 or so lines occur every single time. That was in my first patch set today. > + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); > + if (indio_dev->pollfunc == NULL) { > + ret = -ENOMEM; > + goto error_iio_sw_rb_free;; > + } > + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; > + indio_dev->pollfunc->private_data = indio_dev; > + indio_dev->modes |= INDIO_RING_TRIGGERED; > + return 0; > + > +error_iio_sw_rb_free: > + iio_sw_rb_free(indio_dev->ring); > + return ret; > +} > +EXPORT_SYMBOL(iio_configure_common_ring); > + Small save, but worth having if we can sort the configure function so everyone is happy. > +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) > +{ > + kfree(indio_dev->pollfunc); > + iio_sw_rb_free(indio_dev->ring); > +} > +EXPORT_SYMBOL(iio_unconfigure_common_ring); > + Only purpose of these wrapping functions is to allow for clean Kconfig selection of whether ring is enable or not. I have just sent out a patch that adds relevant stubs to the core allowing these to go from all drivers anyway. Glad to get those out of the way! Thanks for making the waste apparent. > +int iio_initialize_common_ring(struct iio_ring_buffer *ring) > +{ > + return iio_ring_buffer_register(ring, 0); > +} > +EXPORT_SYMBOL(iio_initialize_common_ring); > + > +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) > +{ > + iio_ring_buffer_unregister(ring); > +} > +EXPORT_SYMBOL(iio_uninitialize_common_ring); > + > +static int iio_common_trigger_poll(struct iio_dev *dev_info, > + int index, > + s64 timestamp, > + int no_test) > +{ > + struct iio_state *st = iio_dev_get_devdata(dev_info); > + struct iio_trigger *trig = st->trig; > + > + trig->timestamp = timestamp; > + iio_trigger_poll(trig); > + > + return IRQ_HANDLED; > +} > + > +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); You already know from previous emails that there is an issue with this one given in creates a couple of structures. Would have to be a separate instance per driver. > + > +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); > + > +static struct attribute *iio_trigger_attrs[] = { > + &dev_attr_name.attr, > + NULL, > +}; > + > +static const struct attribute_group iio_trigger_attr_group = { > + .attrs = iio_trigger_attrs, > +}; > + Hiding away the bus type requires a copy of the irq already available. > +static int iio_common_trigger_try_reen(struct iio_trigger *trig) > +{ > + struct iio_state *st = trig->private_data; > + enable_irq(st->irq); > + return 0; > +} > + This is far too specific for my liking. It only even applies to the majority of your drivers due to their current simple nature. If you are going to do this unification I'd like to see it post addition of full hardware event handling (I'm intending to do this at somepoint but am low on time currently and only have an adis16350 to play with) Assumptions: 1) Interrupt line is used for dataready and other events. If this isn't true then the driver should be using the event list system at all. Adds overhead to this path for no gain. With some of the adis sensors you have 2 interrupt lines. A sensible option would be to setup one line for dataready and the other for all other events. 2) Assumes that we have data ready on the first interrupt line. Perhaps this makes sense but it isn't a current requirement or even a suggested option. > +static int iio_common_trigger_set_state(struct iio_trigger *trig, > + bool state) > +{ > + struct iio_state *st = trig->private_data; > + struct iio_dev *indio_dev = st->indio_dev; > + int ret = 0; > + > + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); > + ret = st->set_irq(st, state); > + if (state == false) { > + iio_remove_event_from_list(&iio_event_common_trig, > + &indio_dev->interrupts[0] > + ->ev_list); > + flush_scheduled_work(); > + } else { > + iio_add_event_to_list(&iio_event_common_trig, > + &indio_dev->interrupts[0]->ev_list); > + } > + return ret; > +} > + The rest of your factoring out obviously requires the shared driver state structure. This all makes sense if we think that is a desirable thing to do. > +int iio_probe_common_trigger(struct iio_dev *indio_dev) > +{ > + int ret; > + struct iio_state *st = indio_dev->dev_data; > + > + st->trig = iio_allocate_trigger(); > + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); > + if (!st->trig->name) { > + ret = -ENOMEM; > + goto error_free_trig; > + } > + snprintf((char *)st->trig->name, > + IIO_TRIGGER_NAME_LENGTH, > + "iio-dev%d", indio_dev->id); > + st->trig->dev.parent = st->parent_dev; > + st->trig->owner = THIS_MODULE; > + st->trig->private_data = st; > + st->trig->set_trigger_state = &iio_common_trigger_set_state; > + st->trig->try_reenable = &iio_common_trigger_try_reen; > + st->trig->control_attrs = &iio_trigger_attr_group; > + ret = iio_trigger_register(st->trig); > + > + /* select default trigger */ > + indio_dev->trig = st->trig; > + if (ret) > + goto error_free_trig_name; > + > + return 0; > + > +error_free_trig_name: > + kfree(st->trig->name); > +error_free_trig: > + iio_free_trigger(st->trig); > + > + return ret; > +} > +EXPORT_SYMBOL(iio_probe_common_trigger); > + > +void iio_remove_common_trigger(struct iio_dev *indio_dev) > +{ > + struct iio_state *state = indio_dev->dev_data; > + > + iio_trigger_unregister(state->trig); > + kfree(state->trig->name); > + iio_free_trigger(state->trig); > +} > +EXPORT_SYMBOL(iio_remove_common_trigger); snipped rest as it is obvious boiler pate. As an aside. There is an awful lot of repeated code relating to low level device access in the adis drivers. Perhaps that is a good opportunity for unifying code? Maybe we want and adis_library module? Or perhaps a number of the devices can be combined into a single driver? Just a thought that came up whilst looking at that code again. Thanks, Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-25 17:18 ` Jonathan Cameron @ 2010-06-28 7:59 ` Barry Song 2010-06-28 10:26 ` Jonathan Cameron 0 siblings, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-28 7:59 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On Sat, Jun 26, 2010 at 1:18 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > Hi Barry, > > I've dropped back to the original patch for a close analysis of what is > going on. =C2=A0Sorry for the delay in getting to this! > >> Just RFC for discussion. It is not the last patch To keep the change >> lest, i extract the common factor for most iio devices to a common >> ring trigger module. Most devices can use the interfaces in this >> module directly. So copy-paste for ring and trigger is not necessary >> now. > This time I'm going to concentrate of specific issues. > > Note I'm reading the code as being directed at the vast majority > of cases. =C2=A0What you do here fairly radically changes the job of > the device driver. What I don't want to do is end up with > cases where a tiny difference in hardware results in two completely > different approaches being needed to write the driver. > > In a fairly illogical process I wrote this from the bottom :) > >> >> For iio core changes: >> 1. extract xxx_state to iio_state and add a private data to contain >> chip-specific data >> 2. extract all xxx_ring/xxx_trigger api to common api >> >> Index: drivers/staging/iio/iio.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/iio.h (revision 8893) >> +++ drivers/staging/iio/iio.h (working copy) >> @@ -447,4 +447,46 @@ >> >> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >> + >> +/** >> + * struct iio_state - hardware level hooks for iio device >> + * @work_trigger_to_ring: bh for triggered event handling >> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if new inte= rrupt has been triggered >> + * @last_timestamp: =C2=A0passing timestamp from th to bh of interrupt = handler >> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 industr= ial I/O device structure >> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready trigger r= egistered with iio >> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0transmit buffer >> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0recieve buffer >> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mu= tex to protect tx and rx >> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0interru= pt number >> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the disab= le/enable of external interrupt >> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware by = spi/i2c. >> + **/ >> +struct iio_state { >> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 *parent_dev; >> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_trigger_to_ring; >> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0*indio_dev; >> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0*trig; > > Not all drivers will want shared centralized buffers. =C2=A0Simple > devices might use the various spi and i2c functions that allocate > data storage as needed within the functions. >> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; > > Assumes single irq (lot of adis devices can have several) and makes > a copy of it to get round deliberate hiding of bus info. >> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); > > My issues with this are given where it is used. >> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); > > (as uncommented above) This is used to hide the bus specific info. >> + =C2=A0 =C2=A0 void *priv; >> +}; >> + >> +static inline void iio_state_set_privdata(struct iio_state *st, void *d= ata) >> +{ >> + =C2=A0 =C2=A0 st->priv =3D data; >> +} >> + >> +static inline void * iio_state_get_privdata(struct iio_state *st) >> +{ >> + =C2=A0 =C2=A0 return st->priv; >> +} >> + >> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >> Index: drivers/staging/iio/common-ring-trigger.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >> @@ -0,0 +1,277 @@ >> +/* The software ring with trigger which can be used by most drivers >> + * >> + * Copyright (c) 2010 Barry Song >> + * >> + * This program is free software; you can redistribute it and/or modify= it >> + * under the terms of the GNU General Public License version 2 as publi= shed by >> + * the Free Software Foundation. >> + * >> + */ >> +#include <linux/kernel.h> >> +#include <linux/device.h> >> +#include <linux/interrupt.h> >> +#include <linux/fs.h> >> +#include <linux/poll.h> >> +#include <linux/module.h> >> +#include <linux/cdev.h> >> +#include <linux/slab.h> >> + >> +#include "iio.h" >> +#include "ring_generic.h" >> +#include "trigger.h" >> +#include "ring_sw.h" >> + >> +/* >> + * combine_8_to_16(): utility function to munge to u8s into u16 >> + */ >> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >> +{ >> + =C2=A0 =C2=A0 u16 _lower =3D lower; >> + =C2=A0 =C2=A0 u16 _upper =3D upper; >> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >> +} >> + >> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio_dev); >> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; >> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >> +} >> + > We discussed various options for this, but I'm personally yet to be > convinced that we aren't making the driver code much harder to follow > for the sake of saving lines of code. > > I'm also not sure that the approach currently used here is the right > way to do it in any driver which doesn't help. =C2=A0One thing I would > like to do is to loose the additional data copy required by the current > approach of building a local record by copying form the raw data, then > copying this record into the buffer. > > Preallocating space is easy enough with kfifo so I will probably do > a rework of those patches shortly. For my sw_ring buffer I'm not sure > if it can be easily done, but I'll look into it. That main problem here is that the data layout is not coincident for kinds of chips. But the SW ring procedure is needed by all drivers. My idea is letting all the following done in bottom level driver: if (st->indio_dev->scan_count) if (st->hw_read_ring(st, st->rx) >=3D 0) for (; i < st->indio_dev->scan_count; i++) { data[i] =3D combine_8_to_16(st->rx[i*2+1], ... *((s64 *)(data + ((i + 3)/4)*4)) =3D st->last_timestamp; Then the flow will be: 1. allocate buffer to hold data 2. fill the buffer according to special data layout 3. store_to ring 4. notify the event The procedure is common for all chips using SW ring, only step 2 need be instantized. Then adding hook named get_ring_elemants(), which read HW and organize data layout, is ok in fact. > >> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_s, str= uct iio_state, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >> + >> + =C2=A0 =C2=A0 int i =3D 0; >> + =C2=A0 =C2=A0 s16 *data; >> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd(st->i= ndio_dev->ring); >> + >> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->par= ent_dev, "memory alloc failed in ring bh"); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, st-= >rx) >=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = for (; i < st->indio_dev->scan_count; i++) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 st->rx[i*2]); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = } >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte bou= ndary */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(data = + ((i + 3)/4)*4)) =3D st->last_timestamp; >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->in= dio_dev->ring, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(u8 *)data, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0st->last_timestamp); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->trig= ); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >> +} >> + > > This one is pretty specific, though only in the central > section working out the size. Can we come up with an easy way to > share the rest of the code? > > The previous discussion including some possible solutions. > I'm yet to be convinced that there is a clean way to do the equivalent > of this given the large amount of knowledge your shared code would have > to have about the underlying data. Here the main problem is sizeof(16) is thinked suitable for all chips. Could we add a size_per_element field, then we calucate the total bpd according to the size_per_element and scan_count? >> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 size_t size; >> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, if not = fail*/ >> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_timestamp= )) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >> + >> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_timestam= p) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = if (indio_dev->scan_count) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * sizeof(s16)= ) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 & ~(sizeof(s64) - 1)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = else /* Timestamp only =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = size =3D indio_dev->scan_count*sizeof(s16); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->access.set_= bpd(indio_dev->ring, size); >> + =C2=A0 =C2=A0 } >> + >> + =C2=A0 =C2=A0 return 0; >> +} >> + > > Agree entirely with the next two. =C2=A0Have moved to industrialio-trigge= r > in todays first patch set. =C2=A0They apply in all current cases and > for that matter in any I have yet thought up. Acked. >> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_a= ttach_poll_func(indio_dev->trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >> +} >> + >> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger_d= ettach_poll_func(indio_dev->trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >> +} > > >> + >> +int iio_configure_common_ring(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 int ret =3D 0; >> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_= bh_to_ring); >> + > One reason I'm not keen on this as is, is that it means that all > drivers using this code have to use the same buffer implementation. > I'm very keen to make this selectable on a per driver basis. Why can't all devices by SW rings use the same buffer implementation? Why do they want a different SW ring? > Obviously we could add hooks to make that work, but then we begin > to destroy the point of your patch. > >> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >> + =C2=A0 =C2=A0 if (!ring) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >> + >> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); > > As discussed above. This one is actually a bit of a pain. >> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; > These last two are the same for all triggered software ring buffers, > so I've moved the code into industrialio-trigger.c for now. >> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; >> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; >> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >> + > > This makes it clear that it is sensible to have an alloc_pollfunc functio= n > as the next 8 or so lines occur every single time. =C2=A0That was in my f= irst > patch set today. Acked. >> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollf= unc), GFP_KERNEL); >> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_free;; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_common_ring= _poll_func_th; >> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >> + =C2=A0 =C2=A0 return 0; >> + >> +error_iio_sw_rb_free: >> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >> + =C2=A0 =C2=A0 return ret; >> +} >> +EXPORT_SYMBOL(iio_configure_common_ring); >> + > Small save, but worth having if we can sort the configure function so > everyone is happy. >> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >> +} >> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >> + > > Only purpose of these wrapping functions is to allow for clean > Kconfig selection of whether ring is enable or not. =C2=A0I have just > sent out a patch that adds relevant stubs to the core allowing these > to go from all drivers anyway. =C2=A0Glad to get those out of the way! > Thanks for making the waste apparent. Acked. >> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >> +{ >> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >> +} >> +EXPORT_SYMBOL(iio_initialize_common_ring); >> + >> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >> +{ >> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >> +} >> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >> + >> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_info); >> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >> + >> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >> + >> + =C2=A0 =C2=A0 return IRQ_HANDLED; >> +} >> + >> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); > You already know from previous emails that there is an issue with > this one given in creates a couple of structures. =C2=A0Would have > to be a separate instance per driver. Yes. Here i will give a seperate instance per driver. >> + >> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >> + >> +static struct attribute *iio_trigger_attrs[] =3D { >> + =C2=A0 =C2=A0 &dev_attr_name.attr, >> + =C2=A0 =C2=A0 NULL, >> +}; >> + >> +static const struct attribute_group iio_trigger_attr_group =3D { >> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >> +}; >> + > > Hiding away the bus type requires a copy of the irq already available. >> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >> + =C2=A0 =C2=A0 enable_irq(st->irq); >> + =C2=A0 =C2=A0 return 0; >> +} >> + > > This is far too specific for my liking. =C2=A0It only even applies to > the majority of your drivers due to their current simple nature. > If you are going to do this unification I'd like to see it post > addition of full hardware event handling (I'm intending to do > this at somepoint but am low on time currently and only have an > adis16350 to play with) > > Assumptions: > 1) Interrupt line is used for dataready and other events. > =C2=A0 =C2=A0 =C2=A0 =C2=A0If this isn't true then the driver should be u= sing the event > =C2=A0 =C2=A0 =C2=A0 =C2=A0list system at all. =C2=A0Adds overhead to thi= s path for no gain. > =C2=A0 =C2=A0 =C2=A0 =C2=A0With some of the adis sensors you have 2 inter= rupt lines. > =C2=A0 =C2=A0 =C2=A0 =C2=A0A sensible option would be to setup one line f= or dataready > =C2=A0 =C2=A0 =C2=A0 =C2=A0and the other for all other events. > 2) Assumes that we have data ready on the first interrupt line. > =C2=A0 =C2=A0 =C2=A0 =C2=A0Perhaps this makes sense but it isn't a curren= t requirement > =C2=A0 =C2=A0 =C2=A0 =C2=A0or even a suggested option. Here we can build the matched pair for interrupt index and trigger name, then we can check the interrupt index by trigger name with the pair. If one device has more than one trigger and one interrupt, we transfer the param of interrupt index to set_irq(), then the process flow can be shared too. Anyway, bottom drivers don't want to implement the trigger_set_state per trigger if the flow is same. >> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >> + =C2=A0 =C2=A0 int ret =3D 0; >> + >> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); >> + =C2=A0 =C2=A0 if (state =3D=3D false) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_list(&= iio_event_common_trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work(); >> + =C2=A0 =C2=A0 } else { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(&iio_e= vent_common_trig, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 return ret; >> +} >> + > > The rest of your factoring out obviously requires the shared driver > state structure. =C2=A0This all makes sense if we think that is a desirab= le > thing to do. >> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 int ret; >> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >> + >> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_= KERNEL); >> + =C2=A0 =C2=A0 if (!st->trig->name) { >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; >> + =C2=A0 =C2=A0 } >> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = IIO_TRIGGER_NAME_LENGTH, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = "iio-dev%d", indio_dev->id); >> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigger_set_= state; >> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try_reen; >> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_group; >> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >> + >> + =C2=A0 =C2=A0 /* select default trigger */ >> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >> + =C2=A0 =C2=A0 if (ret) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_name; >> + >> + =C2=A0 =C2=A0 return 0; >> + >> +error_free_trig_name: >> + =C2=A0 =C2=A0 kfree(st->trig->name); >> +error_free_trig: >> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >> + >> + =C2=A0 =C2=A0 return ret; >> +} >> +EXPORT_SYMBOL(iio_probe_common_trigger); >> + > > >> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >> +{ >> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >> + >> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >> + =C2=A0 =C2=A0 kfree(state->trig->name); >> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >> +} >> +EXPORT_SYMBOL(iio_remove_common_trigger); > > snipped rest as it is obvious boiler pate. > > As an aside. There is an awful lot of repeated code relating to low level > device access in the adis drivers. Perhaps that is a good opportunity for > unifying code? =C2=A0Maybe we want and adis_library module? Or perhaps a = number > of the devices can be combined into a single driver? Just a thought > that came up whilst looking at that code again. Good idea in fact. Many codes are same, for example spi read. But it is really difficult to find the orderliness to build a library for the moment. > > Thanks, > > Jonathan > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-28 7:59 ` Barry Song @ 2010-06-28 10:26 ` Jonathan Cameron 2010-06-30 7:51 ` Barry Song 2010-07-08 10:38 ` Barry Song 0 siblings, 2 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-06-28 10:26 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/28/10 08:59, Barry Song wrote: > On Sat, Jun 26, 2010 at 1:18 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote: >> Hi Barry, >> >> I've dropped back to the original patch for a close analysis of what is >> going on. Sorry for the delay in getting to this! >> >>> Just RFC for discussion. It is not the last patch To keep the change >>> lest, i extract the common factor for most iio devices to a common >>> ring trigger module. Most devices can use the interfaces in this >>> module directly. So copy-paste for ring and trigger is not necessary >>> now. >> This time I'm going to concentrate of specific issues. >> >> Note I'm reading the code as being directed at the vast majority >> of cases. What you do here fairly radically changes the job of >> the device driver. What I don't want to do is end up with >> cases where a tiny difference in hardware results in two completely >> different approaches being needed to write the driver. >> >> In a fairly illogical process I wrote this from the bottom :) >> >>> >>> For iio core changes: >>> 1. extract xxx_state to iio_state and add a private data to contain >>> chip-specific data >>> 2. extract all xxx_ring/xxx_trigger api to common api >>> >>> Index: drivers/staging/iio/iio.h >>> =================================================================== >>> --- drivers/staging/iio/iio.h (revision 8893) >>> +++ drivers/staging/iio/iio.h (working copy) >>> @@ -447,4 +447,46 @@ >>> >>> int iio_get_new_idr_val(struct idr *this_idr); >>> void iio_free_idr_val(struct idr *this_idr, int id); >>> + >>> +/** >>> + * struct iio_state - hardware level hooks for iio device >>> + * @work_trigger_to_ring: bh for triggered event handling >>> + * @inter: used to check if new interrupt has been triggered >>> + * @last_timestamp: passing timestamp from th to bh of interrupt handler >>> + * @indio_dev: industrial I/O device structure >>> + * @trig: data ready trigger registered with iio >>> + * @tx: transmit buffer >>> + * @rx: recieve buffer >>> + * @buf_lock: mutex to protect tx and rx >>> + * @irq: interrupt number >>> + * @set_irq: control the disable/enable of external interrupt >>> + * @hw_read_ring: read ring data from hardware by spi/i2c. >>> + **/ >>> +struct iio_state { >>> + struct device *parent_dev; >>> + struct work_struct work_trigger_to_ring; >>> + s64 last_timestamp; >>> + struct iio_dev *indio_dev; >>> + struct iio_trigger *trig; >> >> Not all drivers will want shared centralized buffers. Simple >> devices might use the various spi and i2c functions that allocate >> data storage as needed within the functions. >>> + u8 *tx; >>> + u8 *rx; >>> + struct mutex buf_lock; >> >> Assumes single irq (lot of adis devices can have several) and makes >> a copy of it to get round deliberate hiding of bus info. >>> + int irq; >>> + int (*set_irq)(struct iio_state *st, bool enable); >> >> My issues with this are given where it is used. >>> + int (*hw_read_ring)(struct iio_state *st, u8 *rx); >> >> (as uncommented above) This is used to hide the bus specific info. >>> + void *priv; >>> +}; >>> + >>> +static inline void iio_state_set_privdata(struct iio_state *st, void *data) >>> +{ >>> + st->priv = data; >>> +} >>> + >>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>> +{ >>> + return st->priv; >>> +} >>> + >>> #endif /* _INDUSTRIAL_IO_H_ */ >>> Index: drivers/staging/iio/common-ring-trigger.c >>> =================================================================== >>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>> @@ -0,0 +1,277 @@ >>> +/* The software ring with trigger which can be used by most drivers >>> + * >>> + * Copyright (c) 2010 Barry Song >>> + * >>> + * This program is free software; you can redistribute it and/or modify it >>> + * under the terms of the GNU General Public License version 2 as published by >>> + * the Free Software Foundation. >>> + * >>> + */ >>> +#include <linux/kernel.h> >>> +#include <linux/device.h> >>> +#include <linux/interrupt.h> >>> +#include <linux/fs.h> >>> +#include <linux/poll.h> >>> +#include <linux/module.h> >>> +#include <linux/cdev.h> >>> +#include <linux/slab.h> >>> + >>> +#include "iio.h" >>> +#include "ring_generic.h" >>> +#include "trigger.h" >>> +#include "ring_sw.h" >>> + >>> +/* >>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>> + */ >>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>> +{ >>> + u16 _lower = lower; >>> + u16 _upper = upper; >>> + return _lower | (_upper << 8); >>> +} >>> + >>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>> +{ >>> + struct iio_state *st = iio_dev_get_devdata(indio_dev); >>> + st->last_timestamp = indio_dev->trig->timestamp; >>> + schedule_work(&st->work_trigger_to_ring); >>> +} >>> + >> We discussed various options for this, but I'm personally yet to be >> convinced that we aren't making the driver code much harder to follow >> for the sake of saving lines of code. >> >> I'm also not sure that the approach currently used here is the right >> way to do it in any driver which doesn't help. One thing I would >> like to do is to loose the additional data copy required by the current >> approach of building a local record by copying form the raw data, then >> copying this record into the buffer. >> >> Preallocating space is easy enough with kfifo so I will probably do >> a rework of those patches shortly. For my sw_ring buffer I'm not sure >> if it can be easily done, but I'll look into it. > That main problem here is that the data layout is not coincident for > kinds of chips. But the SW ring procedure is needed by all drivers. My > idea is letting all the following done in bottom level driver: > > if (st->indio_dev->scan_count) > if (st->hw_read_ring(st, st->rx) >= 0) > for (; i < st->indio_dev->scan_count; i++) { > data[i] = combine_8_to_16(st->rx[i*2+1], > ... > *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; > > Then the flow will be: > 1. allocate buffer to hold data Yes. Ideally that will change to be a call to a routine supplied by the buffer implementation as part of a move towards multiple buffer implementations. Note this one would need a hook to have the driver tell it how much space the next step will be needing. This hook would also clean up the buffer allocation code in preenable. > 2. fill the buffer according to special data layout > 3. store_to ring Yup, this will become a paired operation with step 1. (more of a 'done with buffer so it can no be read from the ring, or pushed onto the ring depending on implementation'.) > 4. notify the event > > The procedure is common for all chips using SW ring, only step 2 need > be instantized. Then adding hook named get_ring_elemants(), which read > HW and organize data layout, is ok in fact. Agreed. This way the driver still maintains control of what is going on and is still easy to read, but some of the complexity (error checking etc) is moved to a standard function. My next question is where to put this function. Perhaps within the sw ring implementation? > >> >>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>> +{ >>> + struct iio_state *st >>> + = container_of(work_s, struct iio_state, >>> + work_trigger_to_ring); >>> + >>> + int i = 0; >>> + s16 *data; >>> + size_t datasize = st->indio_dev >>> + ->ring->access.get_bpd(st->indio_dev->ring); >>> + >>> + data = kmalloc(datasize , GFP_KERNEL); >>> + if (data == NULL) { >>> + dev_err(st->parent_dev, "memory alloc failed in ring bh"); >>> + return; >>> + } >>> + >>> + if (st->indio_dev->scan_count) >>> + if (st->hw_read_ring(st, st->rx) >= 0) >>> + for (; i < st->indio_dev->scan_count; i++) { >>> + data[i] = combine_8_to_16(st->rx[i*2+1], >>> + st->rx[i*2]); >>> + } >>> + >>> + /* Guaranteed to be aligned with 8 byte boundary */ >>> + if (st->indio_dev->scan_timestamp) >>> + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; >>> + >>> + st->indio_dev->ring->access.store_to(st->indio_dev->ring, >>> + (u8 *)data, >>> + st->last_timestamp); >>> + >>> + iio_trigger_notify_done(st->indio_dev->trig); >>> + kfree(data); >>> + >>> + return; >>> +} >>> + >> >> This one is pretty specific, though only in the central >> section working out the size. Can we come up with an easy way to >> share the rest of the code? >> >> The previous discussion including some possible solutions. >> I'm yet to be convinced that there is a clean way to do the equivalent >> of this given the large amount of knowledge your shared code would have >> to have about the underlying data. > > Here the main problem is sizeof(16) is thinked suitable for all chips. True for a lot of chips, but not all. I'd rather not have that restriction in there. > Could we add a size_per_element field, then we calucate the total bpd > according to the size_per_element and scan_count? That would work, but is going to be non trivial as we would also want to generate the userspace interface (attributes currently handled by drivers) from these values. As I said above, I'd be more inclined (for now anyway) to let the driver provide a 'get_bpd' call back. It would be handy both here, and in the buffer fill code. With either approach, we then have a nice general form of this function that can be used with all sw buffers, so perhaps this belongs in the ring_sw module as well? > >>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>> +{ >>> + size_t size; >>> + dev_dbg(&indio_dev->dev, "%s\n", __func__); >>> + /* Check if there are any scan elements enabled, if not fail*/ >>> + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) >>> + return -EINVAL; >>> + >>> + if (indio_dev->ring->access.set_bpd) { >>> + if (indio_dev->scan_timestamp) >>> + if (indio_dev->scan_count) >>> + /* Timestamp (aligned to s64) and data */ >>> + size = (((indio_dev->scan_count * sizeof(s16)) >>> + + sizeof(s64) - 1) >>> + & ~(sizeof(s64) - 1)) >>> + + sizeof(s64); >>> + else /* Timestamp only */ >>> + size = sizeof(s64); >>> + else /* Data only */ >>> + size = indio_dev->scan_count*sizeof(s16); >>> + indio_dev->ring->access.set_bpd(indio_dev->ring, size); >>> + } >>> + >>> + return 0; >>> +} >>> + >> >> Agree entirely with the next two. Have moved to industrialio-trigger >> in todays first patch set. They apply in all current cases and >> for that matter in any I have yet thought up. > > Acked. > >>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>> +{ >>> + return indio_dev->trig >>> + ? iio_trigger_attach_poll_func(indio_dev->trig, >>> + indio_dev->pollfunc) >>> + : 0; >>> +} >>> + >>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>> +{ >>> + return indio_dev->trig >>> + ? iio_trigger_dettach_poll_func(indio_dev->trig, >>> + indio_dev->pollfunc) >>> + : 0; >>> +} >> >> >>> + >>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>> +{ >>> + int ret = 0; >>> + struct iio_state *st = indio_dev->dev_data; >>> + struct iio_ring_buffer *ring; >>> + INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring); >>> + >> One reason I'm not keen on this as is, is that it means that all >> drivers using this code have to use the same buffer implementation. >> I'm very keen to make this selectable on a per driver basis. > > Why can't all devices by SW rings use the same buffer implementation? > Why do they want a different SW ring? Although we aren't using it much at the moment, the ability to do this looks to be crucial for the future of IIO. A non exhaustive list of why includes: 1) ring_sw is terrible. I wrote it late one night. No one has ever taken on reviewing it and I for one am far from convinced it is correct. It was only meant to be a proof of concept (though we have been using it for a while in 'production' data capture systems). 2) ring_sw is unsuprisingly a ring buffer. In many applications fifo behaviour is preferable. 3) ring_sw has maximum size of one page. Not good for devices at high rates. 4) lots of interesting work is going on in the area of lockless ring buffers in the kernel at the moment. Whilst then tend to be complex, they have much better scalablity than mine. 5) the buffer hooks are probably the best way to interface to input which people keep requesting. 6) in slow applications a simple locked buffer would be more appropriate unless we are sure there are no downsides to the lockless case. So in the medium term (or short if someone else does it ;) we should have * Something equivalent to ring_sw with all of the hooks for events to userspace etc. * kfifo based fifo. It's simple, but may require excessive locking. (also with this I'm interested in whether I can mess around within spi / i2c subsystems to get some controllers to do scatter gather dma directly into the buffer) * input hooked buffer. * high performance large ring buffer. (I'm waiting to see what comes out of the tracing discussions to see if it is relevant to us). > >> Obviously we could add hooks to make that work, but then we begin >> to destroy the point of your patch. >> >>> + ring = iio_sw_rb_allocate(indio_dev); >>> + if (!ring) { >>> + ret = -ENOMEM; >>> + return ret; >>> + } >>> + indio_dev->ring = ring; >>> + >>> + iio_ring_sw_register_funcs(&ring->access); >> >> As discussed above. This one is actually a bit of a pain. >>> + ring->preenable = &iio_common_ring_preenable; >> These last two are the same for all triggered software ring buffers, >> so I've moved the code into industrialio-trigger.c for now. >>> + ring->postenable = &iio_common_ring_postenable; >>> + ring->predisable = &iio_common_ring_predisable; >>> + ring->owner = THIS_MODULE; >>> + >> >> This makes it clear that it is sensible to have an alloc_pollfunc function >> as the next 8 or so lines occur every single time. That was in my first >> patch set today. > > Acked. > >>> + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); >>> + if (indio_dev->pollfunc == NULL) { >>> + ret = -ENOMEM; >>> + goto error_iio_sw_rb_free;; >>> + } >>> + indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th; >>> + indio_dev->pollfunc->private_data = indio_dev; >>> + indio_dev->modes |= INDIO_RING_TRIGGERED; >>> + return 0; >>> + >>> +error_iio_sw_rb_free: >>> + iio_sw_rb_free(indio_dev->ring); >>> + return ret; >>> +} >>> +EXPORT_SYMBOL(iio_configure_common_ring); >>> + >> Small save, but worth having if we can sort the configure function so >> everyone is happy. >>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>> +{ >>> + kfree(indio_dev->pollfunc); >>> + iio_sw_rb_free(indio_dev->ring); >>> +} >>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>> + >> >> Only purpose of these wrapping functions is to allow for clean >> Kconfig selection of whether ring is enable or not. I have just >> sent out a patch that adds relevant stubs to the core allowing these >> to go from all drivers anyway. Glad to get those out of the way! >> Thanks for making the waste apparent. > > Acked. > >>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>> +{ >>> + return iio_ring_buffer_register(ring, 0); >>> +} >>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>> + >>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>> +{ >>> + iio_ring_buffer_unregister(ring); >>> +} >>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>> + >>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>> + int index, >>> + s64 timestamp, >>> + int no_test) >>> +{ >>> + struct iio_state *st = iio_dev_get_devdata(dev_info); >>> + struct iio_trigger *trig = st->trig; >>> + >>> + trig->timestamp = timestamp; >>> + iio_trigger_poll(trig); >>> + >>> + return IRQ_HANDLED; >>> +} >>> + >>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >> You already know from previous emails that there is an issue with >> this one given in creates a couple of structures. Would have >> to be a separate instance per driver. > > Yes. Here i will give a seperate instance per driver. > >>> + >>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>> + >>> +static struct attribute *iio_trigger_attrs[] = { >>> + &dev_attr_name.attr, >>> + NULL, >>> +}; >>> + >>> +static const struct attribute_group iio_trigger_attr_group = { >>> + .attrs = iio_trigger_attrs, >>> +}; >>> + >> >> Hiding away the bus type requires a copy of the irq already available. >>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>> +{ >>> + struct iio_state *st = trig->private_data; >>> + enable_irq(st->irq); >>> + return 0; >>> +} >>> + >> >> This is far too specific for my liking. It only even applies to >> the majority of your drivers due to their current simple nature. >> If you are going to do this unification I'd like to see it post >> addition of full hardware event handling (I'm intending to do >> this at somepoint but am low on time currently and only have an >> adis16350 to play with) >> >> Assumptions: >> 1) Interrupt line is used for dataready and other events. >> If this isn't true then the driver should be using the event >> list system at all. Adds overhead to this path for no gain. >> With some of the adis sensors you have 2 interrupt lines. >> A sensible option would be to setup one line for dataready >> and the other for all other events. >> 2) Assumes that we have data ready on the first interrupt line. >> Perhaps this makes sense but it isn't a current requirement >> or even a suggested option. > > Here we can build the matched pair for interrupt index and trigger > name, then we can check the interrupt index by trigger name with the > pair. The complexity is not that we might have multiple triggers, its that the physical lines may be doing other things as well such as threshold interrupts etc. Can we hold this chunk of the patch until we have a few more devices implementing events and see where we are at that stage? It certainly looks like there are some savings in code to be made here, but I'm not yet of the best way to do it! > If one device has more than one trigger and one interrupt, we transfer > the param of interrupt index to set_irq(), then the process flow can > be shared too. True. > Anyway, bottom drivers don't want to implement the trigger_set_state > per trigger if the flow is same. I don't follow what you mean here. > >>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>> + bool state) >>> +{ >>> + struct iio_state *st = trig->private_data; >>> + struct iio_dev *indio_dev = st->indio_dev; >>> + int ret = 0; >>> + >>> + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); >>> + ret = st->set_irq(st, state); >>> + if (state == false) { >>> + iio_remove_event_from_list(&iio_event_common_trig, >>> + &indio_dev->interrupts[0] >>> + ->ev_list); >>> + flush_scheduled_work(); >>> + } else { >>> + iio_add_event_to_list(&iio_event_common_trig, >>> + &indio_dev->interrupts[0]->ev_list); >>> + } >>> + return ret; >>> +} >>> + >> >> The rest of your factoring out obviously requires the shared driver >> state structure. This all makes sense if we think that is a desirable >> thing to do. >>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>> +{ >>> + int ret; >>> + struct iio_state *st = indio_dev->dev_data; >>> + >>> + st->trig = iio_allocate_trigger(); >>> + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); >>> + if (!st->trig->name) { >>> + ret = -ENOMEM; >>> + goto error_free_trig; >>> + } >>> + snprintf((char *)st->trig->name, >>> + IIO_TRIGGER_NAME_LENGTH, >>> + "iio-dev%d", indio_dev->id); >>> + st->trig->dev.parent = st->parent_dev; >>> + st->trig->owner = THIS_MODULE; >>> + st->trig->private_data = st; >>> + st->trig->set_trigger_state = &iio_common_trigger_set_state; >>> + st->trig->try_reenable = &iio_common_trigger_try_reen; >>> + st->trig->control_attrs = &iio_trigger_attr_group; >>> + ret = iio_trigger_register(st->trig); >>> + >>> + /* select default trigger */ >>> + indio_dev->trig = st->trig; >>> + if (ret) >>> + goto error_free_trig_name; >>> + >>> + return 0; >>> + >>> +error_free_trig_name: >>> + kfree(st->trig->name); >>> +error_free_trig: >>> + iio_free_trigger(st->trig); >>> + >>> + return ret; >>> +} >>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>> + >> >> >>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>> +{ >>> + struct iio_state *state = indio_dev->dev_data; >>> + >>> + iio_trigger_unregister(state->trig); >>> + kfree(state->trig->name); >>> + iio_free_trigger(state->trig); >>> +} >>> +EXPORT_SYMBOL(iio_remove_common_trigger); >> >> snipped rest as it is obvious boiler pate. >> >> As an aside. There is an awful lot of repeated code relating to low level >> device access in the adis drivers. Perhaps that is a good opportunity for >> unifying code? Maybe we want and adis_library module? Or perhaps a number >> of the devices can be combined into a single driver? Just a thought >> that came up whilst looking at that code again. > > Good idea in fact. Many codes are same, for example spi read. But it > is really difficult to find the orderliness to build a library for the > moment. One for a later round of clean ups! Perhaps I'll take a look at how easy this would be to do. Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-28 10:26 ` Jonathan Cameron @ 2010-06-30 7:51 ` Barry Song 2010-06-30 14:30 ` Jonathan Cameron 2010-07-08 10:38 ` Barry Song 1 sibling, 1 reply; 31+ messages in thread From: Barry Song @ 2010-06-30 7:51 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 For the moment, these should be common for sw ring: Index: drivers/staging/iio/ring_generic.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/ring_generic.h (revision 8933) +++ drivers/staging/iio/ring_generic.h (working copy) @@ -98,6 +98,7 @@ * @access_id: device id number * @length: [DEVICE] number of datums in ring * @bpd: [DEVICE] size of individual datum including timestamp + * @bpe: [DEVICE] size of individual attribution value * @loopcount: [INTERN] number of times the ring has looped * @access_handler: [INTERN] chrdev access handling * @ev_int: [INTERN] chrdev interface for the event chrdev @@ -119,6 +120,7 @@ int access_id; int length; int bpd; + int bpe; int loopcount; struct iio_handler access_handler; struct iio_event_interface ev_int; Index: drivers/staging/iio/ring_sw.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/ring_sw.c (revision 8933) +++ drivers/staging/iio/ring_sw.c (working copy) @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/workqueue.h> #include "ring_sw.h" +#include "trigger.h" static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, int bytes_per_datum, int length) @@ -431,5 +432,74 @@ iio_put_ring_buffer(r); } EXPORT_SYMBOL(iio_sw_rb_free); + +void iio_sw_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct iio_state *st + =3D container_of(work_s, struct iio_state, + work_trigger_to_ring); + int len =3D 0; + size_t datasize =3D st->indio_dev + ->ring->access.get_bpd(st->indio_dev->ring); + char *data =3D kmalloc(datasize , GFP_KERNEL); + + if (data =3D=3D NULL) { + dev_err(st->parent_dev, "memory alloc failed in ring bh"); + return; + } + + if (st->indio_dev->scan_count) + len =3D st->get_ring_element(st, data); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (st->indio_dev->scan_timestamp) + *(s64 *)(((u32)data + len + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) + =3D st->last_timestamp; + + st->indio_dev->ring->access.store_to(st->indio_dev->ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} +EXPORT_SYMBOL(iio_sw_trigger_bh_to_ring); + +int iio_sw_ring_preenable(struct iio_dev *indio_dev) +{ + size_t size; + dev_dbg(&indio_dev->dev, "%s\n", __func__); + /* Check if there are any scan elements enabled, if not fail*/ + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) + return -EINVAL; + if (indio_dev->ring->access.set_bpd) { + if (indio_dev->scan_timestamp) + if (indio_dev->scan_count) + /* Timestamp (aligned to s64) and data */ + size =3D (((indio_dev->scan_count * indio_dev->ring->bpe) + + sizeof(s64) - 1) + & ~(sizeof(s64) - 1)) + + sizeof(s64); + else /* Timestamp only */ + size =3D sizeof(s64); + else /* Data only */ + size =3D indio_dev->scan_count * indio_dev->ring->bpe; + indio_dev->ring->access.set_bpd(indio_dev->ring, size); + } + + return 0; +} +EXPORT_SYMBOL(iio_sw_ring_preenable); + +void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct iio_state *st =3D iio_dev_get_devdata(indio_dev); + st->last_timestamp =3D time; + schedule_work(&st->work_trigger_to_ring); +} +EXPORT_SYMBOL(iio_sw_poll_func_th); + MODULE_DESCRIPTION("Industrialio I/O software ring buffer"); MODULE_LICENSE("GPL"); Index: drivers/staging/iio/iio.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- drivers/staging/iio/iio.h (revision 8933) +++ drivers/staging/iio/iio.h (working copy) @@ -447,4 +447,34 @@ int iio_get_new_idr_val(struct idr *this_idr); void iio_free_idr_val(struct idr *this_idr, int id); + +/** + * struct iio_state - hardware level hooks for iio device + * @work_trigger_to_ring: bh for triggered event handling + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @get_ring_element: read ring data from hardware by spi/i2c and fill buffer. + * @last_timestamp: time stamp the last data for ring is read + * @priv: hold private data special to chips + **/ +struct iio_state { + struct device *parent_dev; + struct work_struct work_trigger_to_ring; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + int (*get_ring_element)(struct iio_state *st, u8 *buf); + s64 last_timestamp; + void *priv; +}; + +static inline void iio_state_set_privdata(struct iio_state *st, void *data= ) +{ + st->priv =3D data; +} + +static inline void * iio_state_get_privdata(struct iio_state *st) +{ + return st->priv; +} + #endif /* _INDUSTRIAL_IO_H_ */ On Mon, Jun 28, 2010 at 6:26 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 06/28/10 08:59, Barry Song wrote: >> On Sat, Jun 26, 2010 at 1:18 AM, Jonathan Cameron <jic23@cam.ac.uk> wrot= e: >>> Hi Barry, >>> >>> I've dropped back to the original patch for a close analysis of what is >>> going on. =C2=A0Sorry for the delay in getting to this! >>> >>>> Just RFC for discussion. It is not the last patch To keep the change >>>> lest, i extract the common factor for most iio devices to a common >>>> ring trigger module. Most devices can use the interfaces in this >>>> module directly. So copy-paste for ring and trigger is not necessary >>>> now. >>> This time I'm going to concentrate of specific issues. >>> >>> Note I'm reading the code as being directed at the vast majority >>> of cases. =C2=A0What you do here fairly radically changes the job of >>> the device driver. What I don't want to do is end up with >>> cases where a tiny difference in hardware results in two completely >>> different approaches being needed to write the driver. >>> >>> In a fairly illogical process I wrote this from the bottom :) >>> >>>> >>>> For iio core changes: >>>> 1. extract xxx_state to iio_state and add a private data to contain >>>> chip-specific data >>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>> >>>> Index: drivers/staging/iio/iio.h >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/iio.h (revision 8893) >>>> +++ drivers/staging/iio/iio.h (working copy) >>>> @@ -447,4 +447,46 @@ >>>> >>>> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >>>> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >>>> + >>>> +/** >>>> + * struct iio_state - hardware level hooks for iio device >>>> + * @work_trigger_to_ring: bh for triggered event handling >>>> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if new in= terrupt has been triggered >>>> + * @last_timestamp: =C2=A0passing timestamp from th to bh of interrup= t handler >>>> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indus= trial I/O device structure >>>> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready trigger= registered with iio >>>> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0transmit buffer >>>> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0recieve buffer >>>> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= mutex to protect tx and rx >>>> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0inter= rupt number >>>> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the dis= able/enable of external interrupt >>>> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware b= y spi/i2c. >>>> + **/ >>>> +struct iio_state { >>>> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 *parent_dev; >>>> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_trigger_to_ring; >>>> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >>>> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0*indio_dev; >>>> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0*trig; >>> >>> Not all drivers will want shared centralized buffers. =C2=A0Simple >>> devices might use the various spi and i2c functions that allocate >>> data storage as needed within the functions. >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >>>> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; >>> >>> Assumes single irq (lot of adis devices can have several) and makes >>> a copy of it to get round deliberate hiding of bus info. >>>> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >>>> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); >>> >>> My issues with this are given where it is used. >>>> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>> >>> (as uncommented above) This is used to hide the bus specific info. >>>> + =C2=A0 =C2=A0 void *priv; >>>> +}; >>>> + >>>> +static inline void iio_state_set_privdata(struct iio_state *st, void = *data) >>>> +{ >>>> + =C2=A0 =C2=A0 st->priv =3D data; >>>> +} >>>> + >>>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>>> +{ >>>> + =C2=A0 =C2=A0 return st->priv; >>>> +} >>>> + >>>> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >>>> Index: drivers/staging/iio/common-ring-trigger.c >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> @@ -0,0 +1,277 @@ >>>> +/* The software ring with trigger which can be used by most drivers >>>> + * >>>> + * Copyright (c) 2010 Barry Song >>>> + * >>>> + * This program is free software; you can redistribute it and/or modi= fy it >>>> + * under the terms of the GNU General Public License version 2 as pub= lished by >>>> + * the Free Software Foundation. >>>> + * >>>> + */ >>>> +#include <linux/kernel.h> >>>> +#include <linux/device.h> >>>> +#include <linux/interrupt.h> >>>> +#include <linux/fs.h> >>>> +#include <linux/poll.h> >>>> +#include <linux/module.h> >>>> +#include <linux/cdev.h> >>>> +#include <linux/slab.h> >>>> + >>>> +#include "iio.h" >>>> +#include "ring_generic.h" >>>> +#include "trigger.h" >>>> +#include "ring_sw.h" >>>> + >>>> +/* >>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>> + */ >>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>> +{ >>>> + =C2=A0 =C2=A0 u16 _lower =3D lower; >>>> + =C2=A0 =C2=A0 u16 _upper =3D upper; >>>> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >>>> +} >>>> + >>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio_dev= ); >>>> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; >>>> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >>>> +} >>>> + >>> We discussed various options for this, but I'm personally yet to be >>> convinced that we aren't making the driver code much harder to follow >>> for the sake of saving lines of code. >>> >>> I'm also not sure that the approach currently used here is the right >>> way to do it in any driver which doesn't help. =C2=A0One thing I would >>> like to do is to loose the additional data copy required by the current >>> approach of building a local record by copying form the raw data, then >>> copying this record into the buffer. >>> >>> Preallocating space is easy enough with kfifo so I will probably do >>> a rework of those patches shortly. For my sw_ring buffer I'm not sure >>> if it can be easily done, but I'll look into it. >> That main problem here is that the data layout is not coincident for >> kinds of chips. But the SW ring procedure is needed by all drivers. My >> idea is letting all the following done in bottom level driver: >> >> if (st->indio_dev->scan_count) >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, st->rx) >=3D 0) >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (; i <= st->indio_dev->scan_count; i++) { >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0... >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *((s64 *)= (data + ((i + 3)/4)*4)) =3D st->last_timestamp; >> >> Then the flow will be: >> 1. allocate buffer to hold data > Yes. =C2=A0Ideally that will change to be a call to a routine supplied by= the > buffer implementation as part of a move towards multiple buffer implement= ations. > Note this one would need a hook to have the driver tell it how much space= the > next step will be needing. =C2=A0This hook would also clean up the buffer= allocation > code in preenable. > >> 2. fill the buffer according to special data layout >> 3. store_to ring > Yup, this will become a paired operation with step 1. =C2=A0(more of a 'd= one > with buffer so it can no be read from the ring, or pushed onto the ring > depending on implementation'.) >> 4. notify the event >> >> The procedure is common for all chips using SW ring, only step 2 need >> be instantized. Then adding hook named get_ring_elemants(), which read >> HW and organize data layout, =C2=A0is ok in fact. > Agreed. =C2=A0This way the driver still maintains control of what is goin= g on > and is still easy to read, but some of the complexity (error checking etc= ) > is moved to a standard function. =C2=A0My next question is where to put t= his function. > Perhaps within the sw ring implementation? > >> >>> >>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_s, s= truct iio_state, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >>>> + >>>> + =C2=A0 =C2=A0 int i =3D 0; >>>> + =C2=A0 =C2=A0 s16 *data; >>>> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd(st-= >indio_dev->ring); >>>> + >>>> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->p= arent_dev, "memory alloc failed in ring bh"); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >>>> + >>>> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, s= t->rx) >=3D 0) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 for (; i < st->indio_dev->scan_count; i++) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 st->rx[i*2]); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 } >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte b= oundary */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(dat= a + ((i + 3)/4)*4)) =3D st->last_timestamp; >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->= indio_dev->ring, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0(u8 *)data, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0st->last_timestamp); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->tr= ig); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> +} >>>> + >>> >>> This one is pretty specific, though only in the central >>> section working out the size. Can we come up with an easy way to >>> share the rest of the code? >>> >>> The previous discussion including some possible solutions. >>> I'm yet to be convinced that there is a clean way to do the equivalent >>> of this given the large amount of knowledge your shared code would have >>> to have about the underlying data. >> >> Here the main problem is sizeof(16) is thinked suitable for all chips. > True for a lot of chips, but not all. =C2=A0I'd rather not have that rest= riction > in there. >> Could we add a size_per_element field, then we calucate the total bpd >> according to the size_per_element and scan_count? > That would work, but is going to be non trivial as we would also want to > generate the userspace interface (attributes currently handled by drivers= ) > from these values. > > As I said above, I'd be more inclined (for now anyway) to let the driver = provide > a 'get_bpd' call back. =C2=A0It would be handy both here, and in the buff= er > fill code. > > With either approach, we then have a nice general form of this function t= hat > can be used with all sw buffers, so perhaps this belongs in the ring_sw > module as well? >> >>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 size_t size; >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, if no= t fail*/ >>>> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_timesta= mp)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >>>> + >>>> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_timest= amp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 if (indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * sizeof(= s16)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 & ~(sizeof(s64) - 1)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 else /* Timestamp only =C2=A0*/ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 size =3D indio_dev->scan_count*sizeof(s16); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->access.se= t_bpd(indio_dev->ring, size); >>>> + =C2=A0 =C2=A0 } >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>> >>> Agree entirely with the next two. =C2=A0Have moved to industrialio-trig= ger >>> in todays first patch set. =C2=A0They apply in all current cases and >>> for that matter in any I have yet thought up. >> >> Acked. >> >>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _attach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>>> + >>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _dettach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>> >>> >>>> + >>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >>>> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_trigge= r_bh_to_ring); >>>> + >>> One reason I'm not keen on this as is, is that it means that all >>> drivers using this code have to use the same buffer implementation. >>> I'm very keen to make this selectable on a per driver basis. >> >> Why can't all devices by SW rings use the same buffer implementation? >> Why do they want a different SW ring? > Although we aren't using it much at the moment, the ability to do this lo= oks > to be crucial for the future of IIO. =C2=A0A non exhaustive list of why i= ncludes: > > 1) ring_sw is terrible. =C2=A0I wrote it late one night. No one has ever = taken > =C2=A0 on reviewing it and I for one am far from convinced it is correct.= It was only > =C2=A0 meant to be a proof of concept (though we have been using it for a= while in > =C2=A0 'production' data capture systems). > > 2) ring_sw is unsuprisingly a ring buffer. =C2=A0In many applications fif= o behaviour > =C2=A0 is preferable. > > 3) ring_sw has maximum size of one page. =C2=A0Not good for devices at hi= gh rates. > > 4) lots of interesting work is going on in the area of lockless ring buff= ers in > =C2=A0 the kernel at the moment. =C2=A0Whilst then tend to be complex, th= ey have much better > =C2=A0 scalablity than mine. > > 5) the buffer hooks are probably the best way to interface to input which= people > =C2=A0 keep requesting. > > 6) in slow applications a simple locked buffer would be more appropriate = unless we > =C2=A0 are sure there are no downsides to the lockless case. > > So in the medium term (or short if someone else does it ;) =C2=A0we shoul= d have > > * Something equivalent to ring_sw with all of the hooks for events to use= rspace etc. > * kfifo based fifo. =C2=A0It's simple, but may require excessive locking.= (also with this > =C2=A0I'm interested in whether I can mess around within spi / i2c subsys= tems to get > =C2=A0some controllers to do scatter gather dma directly into the buffer) > * input hooked buffer. > * high performance large ring buffer. =C2=A0(I'm waiting to see what come= s out of the tracing > =C2=A0discussions to see if it is relevant to us). > > >> >>> Obviously we could add hooks to make that work, but then we begin >>> to destroy the point of your patch. >>> >>>> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >>>> + =C2=A0 =C2=A0 if (!ring) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >>>> + >>>> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); >>> >>> As discussed above. This one is actually a bit of a pain. >>>> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; >>> These last two are the same for all triggered software ring buffers, >>> so I've moved the code into industrialio-trigger.c for now. >>>> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; >>>> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; >>>> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >>>> + >>> >>> This makes it clear that it is sensible to have an alloc_pollfunc funct= ion >>> as the next 8 or so lines occur every single time. =C2=A0That was in my= first >>> patch set today. >> >> Acked. >> >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pol= lfunc), GFP_KERNEL); >>>> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_free;= ; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_common_ri= ng_poll_func_th; >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >>>> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_iio_sw_rb_free: >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>> + >>> Small save, but worth having if we can sort the configure function so >>> everyone is happy. >>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>> + >>> >>> Only purpose of these wrapping functions is to allow for clean >>> Kconfig selection of whether ring is enable or not. =C2=A0I have just >>> sent out a patch that adds relevant stubs to the core allowing these >>> to go from all drivers anyway. =C2=A0Glad to get those out of the way! >>> Thanks for making the waste apparent. >> >> Acked. >> >>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >>>> +} >>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>> + >>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>> + >>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_info)= ; >>>> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >>>> + >>>> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >>>> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >>>> + >>>> + =C2=A0 =C2=A0 return IRQ_HANDLED; >>>> +} >>>> + >>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>> You already know from previous emails that there is an issue with >>> this one given in creates a couple of structures. =C2=A0Would have >>> to be a separate instance per driver. >> >> Yes. Here i will give a seperate instance per driver. >> >>>> + >>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>> + >>>> +static struct attribute *iio_trigger_attrs[] =3D { >>>> + =C2=A0 =C2=A0 &dev_attr_name.attr, >>>> + =C2=A0 =C2=A0 NULL, >>>> +}; >>>> + >>>> +static const struct attribute_group iio_trigger_attr_group =3D { >>>> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >>>> +}; >>>> + >>> >>> Hiding away the bus type requires a copy of the irq already available. >>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 enable_irq(st->irq); >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>> >>> This is far too specific for my liking. =C2=A0It only even applies to >>> the majority of your drivers due to their current simple nature. >>> If you are going to do this unification I'd like to see it post >>> addition of full hardware event handling (I'm intending to do >>> this at somepoint but am low on time currently and only have an >>> adis16350 to play with) >>> >>> Assumptions: >>> 1) Interrupt line is used for dataready and other events. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0If this isn't true then the driver should be= using the event >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0list system at all. =C2=A0Adds overhead to t= his path for no gain. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0With some of the adis sensors you have 2 int= errupt lines. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0A sensible option would be to setup one line= for dataready >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0and the other for all other events. >>> 2) Assumes that we have data ready on the first interrupt line. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0Perhaps this makes sense but it isn't a curr= ent requirement >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0or even a suggested option. >> >> Here we can build the matched pair for interrupt index =C2=A0and trigger >> name, then we can check the interrupt index by trigger name with the >> pair. > The complexity is not that we might have multiple triggers, its that > the physical lines may be doing other things as well such as threshold > interrupts etc. =C2=A0Can we hold this chunk of the patch until we have a= few > more devices implementing events and see where we are at that stage? > > It certainly looks like there are some savings in code to be made > here, but I'm not yet of the best way to do it! > >> If one device has more than one trigger and one interrupt, we transfer >> the param of interrupt index to set_irq(), then the process flow can >> be shared too. > True. >> Anyway, bottom drivers don't want to implement the trigger_set_state >> per trigger if the flow is same. > I don't follow what you mean here. >> >>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state)= ; >>>> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); >>>> + =C2=A0 =C2=A0 if (state =3D=3D false) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_list= (&iio_event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work(); >>>> + =C2=A0 =C2=A0 } else { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(&iio= _event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> + >>> >>> The rest of your factoring out obviously requires the shared driver >>> state structure. =C2=A0This all makes sense if we think that is a desir= able >>> thing to do. >>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >>>> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GF= P_KERNEL); >>>> + =C2=A0 =C2=A0 if (!st->trig->name) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 IIO_TRIGGER_NAME_LENGTH, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "iio-dev%d", indio_dev->id); >>>> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >>>> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >>>> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >>>> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigger_se= t_state; >>>> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try_ree= n; >>>> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_group; >>>> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 /* select default trigger */ >>>> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >>>> + =C2=A0 =C2=A0 if (ret) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_name; >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_free_trig_name: >>>> + =C2=A0 =C2=A0 kfree(st->trig->name); >>>> +error_free_trig: >>>> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>> + >>> >>> >>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >>>> + =C2=A0 =C2=A0 kfree(state->trig->name); >>>> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >>>> +} >>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>> >>> snipped rest as it is obvious boiler pate. >>> >>> As an aside. There is an awful lot of repeated code relating to low lev= el >>> device access in the adis drivers. Perhaps that is a good opportunity f= or >>> unifying code? =C2=A0Maybe we want and adis_library module? Or perhaps = a number >>> of the devices can be combined into a single driver? Just a thought >>> that came up whilst looking at that code again. >> >> Good idea in fact. Many codes are same, for example spi read. But it >> is really difficult to find the orderliness to build a library for the >> moment. > One for a later round of clean ups! =C2=A0Perhaps I'll take a look at how > easy this would be to do. > > Jonathan > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-30 7:51 ` Barry Song @ 2010-06-30 14:30 ` Jonathan Cameron 0 siblings, 0 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-06-30 14:30 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On 06/30/10 08:51, Barry Song wrote: > For the moment, these should be common for sw ring: Agreed. Some of it is probably more general than that but we will have wait a while to see which bits! I've had a bit of a play with this and would like to suggest moving things around to move to more of a 'helper' structure and functions, there for convenience of the drivers rather than your suggestion of a higher level structure which the drivers extend. Anyhow, RFC on that to follow shortly! > > Index: drivers/staging/iio/ring_generic.h > =================================================================== > --- drivers/staging/iio/ring_generic.h (revision 8933) > +++ drivers/staging/iio/ring_generic.h (working copy) > @@ -98,6 +98,7 @@ > * @access_id: device id number > * @length: [DEVICE] number of datums in ring > * @bpd: [DEVICE] size of individual datum including timestamp Good solution. May cause use issues with devices where this value is not constant for all channels but there aren't any devices doing that in the tree at the moment. > + * @bpe: [DEVICE] size of individual attribution value > * @loopcount: [INTERN] number of times the ring has looped > * @access_handler: [INTERN] chrdev access handling > * @ev_int: [INTERN] chrdev interface for the event chrdev > @@ -119,6 +120,7 @@ > int access_id; > int length; > int bpd; > + int bpe; > int loopcount; > struct iio_handler access_handler; > struct iio_event_interface ev_int; > Index: drivers/staging/iio/ring_sw.c > =================================================================== > --- drivers/staging/iio/ring_sw.c (revision 8933) > +++ drivers/staging/iio/ring_sw.c (working copy) > @@ -13,6 +13,7 @@ > #include <linux/device.h> > #include <linux/workqueue.h> > #include "ring_sw.h" > +#include "trigger.h" > > static inline int __iio_allocate_sw_ring_buffer(struct > iio_sw_ring_buffer *ring, > int bytes_per_datum, int length) > @@ -431,5 +432,74 @@ > iio_put_ring_buffer(r); > } > EXPORT_SYMBOL(iio_sw_rb_free); > + > +void iio_sw_trigger_bh_to_ring(struct work_struct *work_s) > +{ > + struct iio_state *st > + = container_of(work_s, struct iio_state, > + work_trigger_to_ring); > + int len = 0; > + size_t datasize = st->indio_dev > + ->ring->access.get_bpd(st->indio_dev->ring); > + char *data = kmalloc(datasize , GFP_KERNEL); > + > + if (data == NULL) { > + dev_err(st->parent_dev, "memory alloc failed in ring bh"); > + return; > + } > + > + if (st->indio_dev->scan_count) > + len = st->get_ring_element(st, data); > + > + /* Guaranteed to be aligned with 8 byte boundary */ > + if (st->indio_dev->scan_timestamp) > + *(s64 *)(((u32)data + len + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) > + = st->last_timestamp; > + Not all users of sw ring get the timestamp from the trigger. For devices (max1363 for example) that use the bus read itself to trigger the capture the timestamp comes from equivalent of your get_ring_element call. Dealing with those devices is a job for another day! > + st->indio_dev->ring->access.store_to(st->indio_dev->ring, > + (u8 *)data, > + st->last_timestamp); > + > + iio_trigger_notify_done(st->indio_dev->trig); > + kfree(data); > + > + return; > +} > +EXPORT_SYMBOL(iio_sw_trigger_bh_to_ring); > + Acked this one (I have put together a patch series using this in all by max1363 as things are currently a fair bit different in there) Will post shortly. > +int iio_sw_ring_preenable(struct iio_dev *indio_dev) > +{ > + size_t size; > + dev_dbg(&indio_dev->dev, "%s\n", __func__); > + /* Check if there are any scan elements enabled, if not fail*/ > + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) > + return -EINVAL; > + if (indio_dev->ring->access.set_bpd) { > + if (indio_dev->scan_timestamp) > + if (indio_dev->scan_count) > + /* Timestamp (aligned to s64) and data */ > + size = (((indio_dev->scan_count * indio_dev->ring->bpe) > + + sizeof(s64) - 1) > + & ~(sizeof(s64) - 1)) > + + sizeof(s64); > + else /* Timestamp only */ > + size = sizeof(s64); > + else /* Data only */ > + size = indio_dev->scan_count * indio_dev->ring->bpe; > + indio_dev->ring->access.set_bpd(indio_dev->ring, size); > + } > + > + return 0; > +} > +EXPORT_SYMBOL(iio_sw_ring_preenable); > + Where do we set dev data? If at all possible I'd like state to be in the device_state structure rather than the other way around. That way around it acts as a helper class without adding an intermediate layer to these drivers. Also reduces us to a single allocation call rather than allocate an iio_state then allocate the device_state. As you have done here, the iio devdata then points to the iio_state and we use container_of to get to the device_state elements. I've done a quick implementation of the equivalent of this with your iio_state moved into the device specific structure. Will post shortly. > +void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time) > +{ > + struct iio_state *st = iio_dev_get_devdata(indio_dev); > + st->last_timestamp = time; > + schedule_work(&st->work_trigger_to_ring); > +} > +EXPORT_SYMBOL(iio_sw_poll_func_th); > + > MODULE_DESCRIPTION("Industrialio I/O software ring buffer"); > MODULE_LICENSE("GPL"); > Index: drivers/staging/iio/iio.h > =================================================================== > --- drivers/staging/iio/iio.h (revision 8933) > +++ drivers/staging/iio/iio.h (working copy) > @@ -447,4 +447,34 @@ > > int iio_get_new_idr_val(struct idr *this_idr); > void iio_free_idr_val(struct idr *this_idr, int id); > + > +/** > + * struct iio_state - hardware level hooks for iio device > + * @work_trigger_to_ring: bh for triggered event handling > + * @indio_dev: industrial I/O device structure > + * @trig: data ready trigger registered with iio > + * @get_ring_element: read ring data from hardware by spi/i2c and > fill buffer. > + * @last_timestamp: time stamp the last data for ring is read > + * @priv: hold private data special to chips > + **/ > +struct iio_state { This is only used for a single error message. Do we care enough about the detail of that message? This exists deep in iio_dev anyway so lets get it from there. > + struct device *parent_dev; > + struct work_struct work_trigger_to_ring; > + struct iio_dev *indio_dev; This isn't used in this patch. Might fall in a later one but it doesn't want > + struct iio_trigger *trig; > + int (*get_ring_element)(struct iio_state *st, u8 *buf); > + s64 last_timestamp; This goes as well if we embedded it the other way around. > + void *priv; > +}; > + > +static inline void iio_state_set_privdata(struct iio_state *st, void *data) > +{ > + st->priv = data; > +} > + > +static inline void * iio_state_get_privdata(struct iio_state *st) > +{ > + return st->priv; > +} > + > #endif /* _INDUSTRIAL_IO_H_ */ > > > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-06-28 10:26 ` Jonathan Cameron 2010-06-30 7:51 ` Barry Song @ 2010-07-08 10:38 ` Barry Song 2010-07-08 15:04 ` Jonathan Cameron 1 sibling, 1 reply; 31+ messages in thread From: Barry Song @ 2010-07-08 10:38 UTC (permalink / raw) To: Jonathan Cameron Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 On Mon, Jun 28, 2010 at 6:26 PM, Jonathan Cameron <jic23@cam.ac.uk> wrote: > On 06/28/10 08:59, Barry Song wrote: >> On Sat, Jun 26, 2010 at 1:18 AM, Jonathan Cameron <jic23@cam.ac.uk> wrot= e: >>> Hi Barry, >>> >>> I've dropped back to the original patch for a close analysis of what is >>> going on. =C2=A0Sorry for the delay in getting to this! >>> >>>> Just RFC for discussion. It is not the last patch To keep the change >>>> lest, i extract the common factor for most iio devices to a common >>>> ring trigger module. Most devices can use the interfaces in this >>>> module directly. So copy-paste for ring and trigger is not necessary >>>> now. >>> This time I'm going to concentrate of specific issues. >>> >>> Note I'm reading the code as being directed at the vast majority >>> of cases. =C2=A0What you do here fairly radically changes the job of >>> the device driver. What I don't want to do is end up with >>> cases where a tiny difference in hardware results in two completely >>> different approaches being needed to write the driver. >>> >>> In a fairly illogical process I wrote this from the bottom :) >>> >>>> >>>> For iio core changes: >>>> 1. extract xxx_state to iio_state and add a private data to contain >>>> chip-specific data >>>> 2. extract all xxx_ring/xxx_trigger api to common api >>>> >>>> Index: drivers/staging/iio/iio.h >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/iio.h (revision 8893) >>>> +++ drivers/staging/iio/iio.h (working copy) >>>> @@ -447,4 +447,46 @@ >>>> >>>> =C2=A0int iio_get_new_idr_val(struct idr *this_idr); >>>> =C2=A0void iio_free_idr_val(struct idr *this_idr, int id); >>>> + >>>> +/** >>>> + * struct iio_state - hardware level hooks for iio device >>>> + * @work_trigger_to_ring: bh for triggered event handling >>>> + * @inter: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 used to check if new in= terrupt has been triggered >>>> + * @last_timestamp: =C2=A0passing timestamp from th to bh of interrup= t handler >>>> + * @indio_dev: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indus= trial I/O device structure >>>> + * @trig: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data ready trigger= registered with iio >>>> + * @tx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0transmit buffer >>>> + * @rx: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0recieve buffer >>>> + * @buf_lock: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= mutex to protect tx and rx >>>> + * @irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0inter= rupt number >>>> + * @set_irq: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0control the dis= able/enable of external interrupt >>>> + * @hw_read_ring: =C2=A0 =C2=A0 =C2=A0 read ring data from hardware b= y spi/i2c. >>>> + **/ >>>> +struct iio_state { >>>> + =C2=A0 =C2=A0 struct device =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 *parent_dev; >>>> + =C2=A0 =C2=A0 struct work_struct =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0work_trigger_to_ring; >>>> + =C2=A0 =C2=A0 s64 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 last_timestamp; >>>> + =C2=A0 =C2=A0 struct iio_dev =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0*indio_dev; >>>> + =C2=A0 =C2=A0 struct iio_trigger =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0*trig; >>> >>> Not all drivers will want shared centralized buffers. =C2=A0Simple >>> devices might use the various spi and i2c functions that allocate >>> data storage as needed within the functions. >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*tx; >>>> + =C2=A0 =C2=A0 u8 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*rx; >>>> + =C2=A0 =C2=A0 struct mutex =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0buf_lock; >>> >>> Assumes single irq (lot of adis devices can have several) and makes >>> a copy of it to get round deliberate hiding of bus info. >>>> + =C2=A0 =C2=A0 int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 irq; >>>> + =C2=A0 =C2=A0 int (*set_irq)(struct iio_state *st, bool enable); >>> >>> My issues with this are given where it is used. >>>> + =C2=A0 =C2=A0 int (*hw_read_ring)(struct iio_state *st, u8 *rx); >>> >>> (as uncommented above) This is used to hide the bus specific info. >>>> + =C2=A0 =C2=A0 void *priv; >>>> +}; >>>> + >>>> +static inline void iio_state_set_privdata(struct iio_state *st, void = *data) >>>> +{ >>>> + =C2=A0 =C2=A0 st->priv =3D data; >>>> +} >>>> + >>>> +static inline void * iio_state_get_privdata(struct iio_state *st) >>>> +{ >>>> + =C2=A0 =C2=A0 return st->priv; >>>> +} >>>> + >>>> =C2=A0#endif /* _INDUSTRIAL_IO_H_ */ >>>> Index: drivers/staging/iio/common-ring-trigger.c >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0) >>>> @@ -0,0 +1,277 @@ >>>> +/* The software ring with trigger which can be used by most drivers >>>> + * >>>> + * Copyright (c) 2010 Barry Song >>>> + * >>>> + * This program is free software; you can redistribute it and/or modi= fy it >>>> + * under the terms of the GNU General Public License version 2 as pub= lished by >>>> + * the Free Software Foundation. >>>> + * >>>> + */ >>>> +#include <linux/kernel.h> >>>> +#include <linux/device.h> >>>> +#include <linux/interrupt.h> >>>> +#include <linux/fs.h> >>>> +#include <linux/poll.h> >>>> +#include <linux/module.h> >>>> +#include <linux/cdev.h> >>>> +#include <linux/slab.h> >>>> + >>>> +#include "iio.h" >>>> +#include "ring_generic.h" >>>> +#include "trigger.h" >>>> +#include "ring_sw.h" >>>> + >>>> +/* >>>> + * combine_8_to_16(): utility function to munge to u8s into u16 >>>> + */ >>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper) >>>> +{ >>>> + =C2=A0 =C2=A0 u16 _lower =3D lower; >>>> + =C2=A0 =C2=A0 u16 _upper =3D upper; >>>> + =C2=A0 =C2=A0 return _lower | (_upper << 8); >>>> +} >>>> + >>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(indio_dev= ); >>>> + =C2=A0 =C2=A0 st->last_timestamp =3D indio_dev->trig->timestamp; >>>> + =C2=A0 =C2=A0 schedule_work(&st->work_trigger_to_ring); >>>> +} >>>> + >>> We discussed various options for this, but I'm personally yet to be >>> convinced that we aren't making the driver code much harder to follow >>> for the sake of saving lines of code. >>> >>> I'm also not sure that the approach currently used here is the right >>> way to do it in any driver which doesn't help. =C2=A0One thing I would >>> like to do is to loose the additional data copy required by the current >>> approach of building a local record by copying form the raw data, then >>> copying this record into the buffer. >>> >>> Preallocating space is easy enough with kfifo so I will probably do >>> a rework of those patches shortly. For my sw_ring buffer I'm not sure >>> if it can be easily done, but I'll look into it. >> That main problem here is that the data layout is not coincident for >> kinds of chips. But the SW ring procedure is needed by all drivers. My >> idea is letting all the following done in bottom level driver: >> >> if (st->indio_dev->scan_count) >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, st->rx) >=3D 0) >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (; i <= st->indio_dev->scan_count; i++) { >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0... >> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *((s64 *)= (data + ((i + 3)/4)*4)) =3D st->last_timestamp; >> >> Then the flow will be: >> 1. allocate buffer to hold data > Yes. =C2=A0Ideally that will change to be a call to a routine supplied by= the > buffer implementation as part of a move towards multiple buffer implement= ations. > Note this one would need a hook to have the driver tell it how much space= the > next step will be needing. =C2=A0This hook would also clean up the buffer= allocation > code in preenable. > >> 2. fill the buffer according to special data layout >> 3. store_to ring > Yup, this will become a paired operation with step 1. =C2=A0(more of a 'd= one > with buffer so it can no be read from the ring, or pushed onto the ring > depending on implementation'.) >> 4. notify the event >> >> The procedure is common for all chips using SW ring, only step 2 need >> be instantized. Then adding hook named get_ring_elemants(), which read >> HW and organize data layout, =C2=A0is ok in fact. > Agreed. =C2=A0This way the driver still maintains control of what is goin= g on > and is still easy to read, but some of the complexity (error checking etc= ) > is moved to a standard function. =C2=A0My next question is where to put t= his function. > Perhaps within the sw ring implementation? > >> >>> >>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D container_of(work_s, s= truct iio_state, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 work_trigger_to_ring); >>>> + >>>> + =C2=A0 =C2=A0 int i =3D 0; >>>> + =C2=A0 =C2=A0 s16 *data; >>>> + =C2=A0 =C2=A0 size_t datasize =3D st->indio_dev >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ring->access.get_bpd(st-= >indio_dev->ring); >>>> + >>>> + =C2=A0 =C2=A0 data =3D kmalloc(datasize , GFP_KERNEL); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (data =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_err(st->p= arent_dev, "memory alloc failed in ring bh"); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >>>> + >>>> + =C2=A0 =C2=A0 if (st->indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (st->hw_read_ring(st, s= t->rx) >=3D 0) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 for (; i < st->indio_dev->scan_count; i++) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 data[i] =3D combine_8_to_16(st->rx[i*2+1], >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 st->rx[i*2]); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 } >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Guaranteed to be aligned with 8 byte b= oundary */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->indio_dev->scan_timestamp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*((s64 *)(dat= a + ((i + 3)/4)*4)) =3D st->last_timestamp; >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->indio_dev->ring->access.store_to(st->= indio_dev->ring, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0(u8 *)data, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0st->last_timestamp); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0iio_trigger_notify_done(st->indio_dev->tr= ig); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(data); >>>> + >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >>>> +} >>>> + >>> >>> This one is pretty specific, though only in the central >>> section working out the size. Can we come up with an easy way to >>> share the rest of the code? >>> >>> The previous discussion including some possible solutions. >>> I'm yet to be convinced that there is a clean way to do the equivalent >>> of this given the large amount of knowledge your shared code would have >>> to have about the underlying data. >> >> Here the main problem is sizeof(16) is thinked suitable for all chips. > True for a lot of chips, but not all. =C2=A0I'd rather not have that rest= riction > in there. >> Could we add a size_per_element field, then we calucate the total bpd >> according to the size_per_element and scan_count? > That would work, but is going to be non trivial as we would also want to > generate the userspace interface (attributes currently handled by drivers= ) > from these values. > > As I said above, I'd be more inclined (for now anyway) to let the driver = provide > a 'get_bpd' call back. =C2=A0It would be handy both here, and in the buff= er > fill code. > > With either approach, we then have a nice general form of this function t= hat > can be used with all sw buffers, so perhaps this belongs in the ring_sw > module as well? >> >>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 size_t size; >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s\n", __func__); >>>> + =C2=A0 =C2=A0 /* Check if there are any scan elements enabled, if no= t fail*/ >>>> + =C2=A0 =C2=A0 if (!(indio_dev->scan_count || indio_dev->scan_timesta= mp)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -EINVAL; >>>> + >>>> + =C2=A0 =C2=A0 if (indio_dev->ring->access.set_bpd) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (indio_dev->scan_timest= amp) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 if (indio_dev->scan_count) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Timestamp (aligned to s64) and data */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D (((indio_dev->scan_count * sizeof(= s16)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64) - 1) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 & ~(sizeof(s64) - 1)) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 else /* Timestamp only =C2=A0*/ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size =3D sizeof(s64); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else /* Data only */ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 size =3D indio_dev->scan_count*sizeof(s16); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 indio_dev->ring->access.se= t_bpd(indio_dev->ring, size); >>>> + =C2=A0 =C2=A0 } >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>> >>> Agree entirely with the next two. =C2=A0Have moved to industrialio-trig= ger >>> in todays first patch set. =C2=A0They apply in all current cases and >>> for that matter in any I have yet thought up. >> >> Acked. >> >>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _attach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>>> + >>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return indio_dev->trig >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0? iio_trigger= _dettach_poll_func(indio_dev->trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0indio_dev->pollfunc) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0: 0; >>>> +} >>> >>> >>>> + >>>> +int iio_configure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + =C2=A0 =C2=A0 struct iio_ring_buffer *ring; >>>> + =C2=A0 =C2=A0 INIT_WORK(&st->work_trigger_to_ring, iio_common_trigge= r_bh_to_ring); >>>> + >>> One reason I'm not keen on this as is, is that it means that all >>> drivers using this code have to use the same buffer implementation. >>> I'm very keen to make this selectable on a per driver basis. >> >> Why can't all devices by SW rings use the same buffer implementation? >> Why do they want a different SW ring? > Although we aren't using it much at the moment, the ability to do this lo= oks > to be crucial for the future of IIO. =C2=A0A non exhaustive list of why i= ncludes: > > 1) ring_sw is terrible. =C2=A0I wrote it late one night. No one has ever = taken > =C2=A0 on reviewing it and I for one am far from convinced it is correct.= It was only > =C2=A0 meant to be a proof of concept (though we have been using it for a= while in > =C2=A0 'production' data capture systems). > > 2) ring_sw is unsuprisingly a ring buffer. =C2=A0In many applications fif= o behaviour > =C2=A0 is preferable. > > 3) ring_sw has maximum size of one page. =C2=A0Not good for devices at hi= gh rates. > > 4) lots of interesting work is going on in the area of lockless ring buff= ers in > =C2=A0 the kernel at the moment. =C2=A0Whilst then tend to be complex, th= ey have much better > =C2=A0 scalablity than mine. > > 5) the buffer hooks are probably the best way to interface to input which= people > =C2=A0 keep requesting. > > 6) in slow applications a simple locked buffer would be more appropriate = unless we > =C2=A0 are sure there are no downsides to the lockless case. > > So in the medium term (or short if someone else does it ;) =C2=A0we shoul= d have > > * Something equivalent to ring_sw with all of the hooks for events to use= rspace etc. > * kfifo based fifo. =C2=A0It's simple, but may require excessive locking.= (also with this > =C2=A0I'm interested in whether I can mess around within spi / i2c subsys= tems to get > =C2=A0some controllers to do scatter gather dma directly into the buffer) > * input hooked buffer. > * high performance large ring buffer. =C2=A0(I'm waiting to see what come= s out of the tracing > =C2=A0discussions to see if it is relevant to us). > > >> >>> Obviously we could add hooks to make that work, but then we begin >>> to destroy the point of your patch. >>> >>>> + =C2=A0 =C2=A0 ring =3D iio_sw_rb_allocate(indio_dev); >>>> + =C2=A0 =C2=A0 if (!ring) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->ring =3D ring; >>>> + >>>> + =C2=A0 =C2=A0 iio_ring_sw_register_funcs(&ring->access); >>> >>> As discussed above. This one is actually a bit of a pain. >>>> + =C2=A0 =C2=A0 ring->preenable =3D &iio_common_ring_preenable; >>> These last two are the same for all triggered software ring buffers, >>> so I've moved the code into industrialio-trigger.c for now. >>>> + =C2=A0 =C2=A0 ring->postenable =3D &iio_common_ring_postenable; >>>> + =C2=A0 =C2=A0 ring->predisable =3D &iio_common_ring_predisable; >>>> + =C2=A0 =C2=A0 ring->owner =3D THIS_MODULE; >>>> + >>> >>> This makes it clear that it is sensible to have an alloc_pollfunc funct= ion >>> as the next 8 or so lines occur every single time. =C2=A0That was in my= first >>> patch set today. >> >> Acked. >> >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pol= lfunc), GFP_KERNEL); >>>> + =C2=A0 =C2=A0 if (indio_dev->pollfunc =3D=3D NULL) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_iio_sw_rb_free;= ; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->poll_func_main =3D &iio_common_ri= ng_poll_func_th; >>>> + =C2=A0 =C2=A0 indio_dev->pollfunc->private_data =3D indio_dev; >>>> + =C2=A0 =C2=A0 indio_dev->modes |=3D INDIO_RING_TRIGGERED; >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_iio_sw_rb_free: >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_configure_common_ring); >>>> + >>> Small save, but worth having if we can sort the configure function so >>> everyone is happy. >>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 kfree(indio_dev->pollfunc); >>>> + =C2=A0 =C2=A0 iio_sw_rb_free(indio_dev->ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring); >>>> + >>> >>> Only purpose of these wrapping functions is to allow for clean >>> Kconfig selection of whether ring is enable or not. =C2=A0I have just >>> sent out a patch that adds relevant stubs to the core allowing these >>> to go from all drivers anyway. =C2=A0Glad to get those out of the way! >>> Thanks for making the waste apparent. >> >> Acked. >> >>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 return iio_ring_buffer_register(ring, 0); >>>> +} >>>> +EXPORT_SYMBOL(iio_initialize_common_ring); >>>> + >>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring) >>>> +{ >>>> + =C2=A0 =C2=A0 iio_ring_buffer_unregister(ring); >>>> +} >>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring); >>>> + >>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int index, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s64 timestamp, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int no_test) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D iio_dev_get_devdata(dev_info)= ; >>>> + =C2=A0 =C2=A0 struct iio_trigger *trig =3D st->trig; >>>> + >>>> + =C2=A0 =C2=A0 trig->timestamp =3D timestamp; >>>> + =C2=A0 =C2=A0 iio_trigger_poll(trig); >>>> + >>>> + =C2=A0 =C2=A0 return IRQ_HANDLED; >>>> +} >>>> + >>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll); >>> You already know from previous emails that there is an issue with >>> this one given in creates a couple of structures. =C2=A0Would have >>> to be a separate instance per driver. >> >> Yes. Here i will give a seperate instance per driver. >> >>>> + >>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); >>>> + >>>> +static struct attribute *iio_trigger_attrs[] =3D { >>>> + =C2=A0 =C2=A0 &dev_attr_name.attr, >>>> + =C2=A0 =C2=A0 NULL, >>>> +}; >>>> + >>>> +static const struct attribute_group iio_trigger_attr_group =3D { >>>> + =C2=A0 =C2=A0 .attrs =3D iio_trigger_attrs, >>>> +}; >>>> + >>> >>> Hiding away the bus type requires a copy of the irq already available. >>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 enable_irq(st->irq); >>>> + =C2=A0 =C2=A0 return 0; >>>> +} >>>> + >>> >>> This is far too specific for my liking. =C2=A0It only even applies to >>> the majority of your drivers due to their current simple nature. >>> If you are going to do this unification I'd like to see it post >>> addition of full hardware event handling (I'm intending to do >>> this at somepoint but am low on time currently and only have an >>> adis16350 to play with) >>> >>> Assumptions: >>> 1) Interrupt line is used for dataready and other events. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0If this isn't true then the driver should be= using the event >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0list system at all. =C2=A0Adds overhead to t= his path for no gain. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0With some of the adis sensors you have 2 int= errupt lines. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0A sensible option would be to setup one line= for dataready >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0and the other for all other events. >>> 2) Assumes that we have data ready on the first interrupt line. >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0Perhaps this makes sense but it isn't a curr= ent requirement >>> =C2=A0 =C2=A0 =C2=A0 =C2=A0or even a suggested option. >> >> Here we can build the matched pair for interrupt index =C2=A0and trigger >> name, then we can check the interrupt index by trigger name with the >> pair. > The complexity is not that we might have multiple triggers, its that > the physical lines may be doing other things as well such as threshold > interrupts etc. =C2=A0Can we hold this chunk of the patch until we have a= few > more devices implementing events and see where we are at that stage? > > It certainly looks like there are some savings in code to be made > here, but I'm not yet of the best way to do it! > >> If one device has more than one trigger and one interrupt, we transfer >> the param of interrupt index to set_irq(), then the process flow can >> be shared too. > True. >> Anyway, bottom drivers don't want to implement the trigger_set_state >> per trigger if the flow is same. > I don't follow what you mean here. >> >>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool state) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D trig->private_data; >>>> + =C2=A0 =C2=A0 struct iio_dev *indio_dev =3D st->indio_dev; >>>> + =C2=A0 =C2=A0 int ret =3D 0; >>>> + >>>> + =C2=A0 =C2=A0 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state)= ; >>>> + =C2=A0 =C2=A0 ret =3D st->set_irq(st, state); >>>> + =C2=A0 =C2=A0 if (state =3D=3D false) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_remove_event_from_list= (&iio_event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0] >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ->ev_list); >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_scheduled_work(); >>>> + =C2=A0 =C2=A0 } else { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iio_add_event_to_list(&iio= _event_common_trig, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &indio_dev->interrupts[0]->ev_list); >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> + >>> >>> The rest of your factoring out obviously requires the shared driver >>> state structure. =C2=A0This all makes sense if we think that is a desir= able >>> thing to do. >>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 int ret; >>>> + =C2=A0 =C2=A0 struct iio_state *st =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 st->trig =3D iio_allocate_trigger(); >>>> + =C2=A0 =C2=A0 st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GF= P_KERNEL); >>>> + =C2=A0 =C2=A0 if (!st->trig->name) { >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -ENOMEM; >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig; >>>> + =C2=A0 =C2=A0 } >>>> + =C2=A0 =C2=A0 snprintf((char *)st->trig->name, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 IIO_TRIGGER_NAME_LENGTH, >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "iio-dev%d", indio_dev->id); >>>> + =C2=A0 =C2=A0 st->trig->dev.parent =3D st->parent_dev; >>>> + =C2=A0 =C2=A0 st->trig->owner =3D THIS_MODULE; >>>> + =C2=A0 =C2=A0 st->trig->private_data =3D st; >>>> + =C2=A0 =C2=A0 st->trig->set_trigger_state =3D &iio_common_trigger_se= t_state; >>>> + =C2=A0 =C2=A0 st->trig->try_reenable =3D &iio_common_trigger_try_ree= n; >>>> + =C2=A0 =C2=A0 st->trig->control_attrs =3D &iio_trigger_attr_group; >>>> + =C2=A0 =C2=A0 ret =3D iio_trigger_register(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 /* select default trigger */ >>>> + =C2=A0 =C2=A0 indio_dev->trig =3D st->trig; >>>> + =C2=A0 =C2=A0 if (ret) >>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error_free_trig_name; >>>> + >>>> + =C2=A0 =C2=A0 return 0; >>>> + >>>> +error_free_trig_name: >>>> + =C2=A0 =C2=A0 kfree(st->trig->name); >>>> +error_free_trig: >>>> + =C2=A0 =C2=A0 iio_free_trigger(st->trig); >>>> + >>>> + =C2=A0 =C2=A0 return ret; >>>> +} >>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>> + >>> >>> >>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>> +{ >>>> + =C2=A0 =C2=A0 struct iio_state *state =3D indio_dev->dev_data; >>>> + >>>> + =C2=A0 =C2=A0 iio_trigger_unregister(state->trig); >>>> + =C2=A0 =C2=A0 kfree(state->trig->name); >>>> + =C2=A0 =C2=A0 iio_free_trigger(state->trig); >>>> +} >>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>> >>> snipped rest as it is obvious boiler pate. For this, how about we let bottom driver to implement set_trigger_state(), try_reenable(), and control_attrs of trigger, but probe() and remove() can be common like this: drivers/staging/iio/ring_sw.h struct iio_sw_ring_helper_state { struct work_struct work_trigger_to_ring; struct iio_dev *indio_dev; + struct iio_trigger *trig; int (*get_ring_element)(struct iio_sw_ring_helper_state *st, u8 *buf= ); s64 last_timestamp; }; drivers/staging/iio/ring_sw.c +int iio_sw_probe_trigger(struct iio_dev *indio_dev, char *name, struct attribute_group *attr_group) +{ + int ret; + struct iio_sw_ring_helper_state *st =3D (struct iio_sw_ring_helper_state *)indio_dev->dev_data; + st->trig =3D iio_allocate_trigger(); + st->trig->name =3D kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + if (!st->trig->name) { + ret =3D -ENOMEM; + goto error_free_trig; + } + snprintf((char *)st->trig->name, + IIO_TRIGGER_NAME_LENGTH, + "%s%d", name, indio_dev->id); + st->trig->dev.parent =3D st->parent_dev; + st->trig->owner =3D THIS_MODULE; + st->trig->private_data =3D st; + st->trig->control_attrs =3D attr_group; + ret =3D iio_trigger_register(st->trig); + indio_dev->trig =3D st->trig; + if (ret) + goto error_free_trig_name; + return 0; +error_free_trig_name: kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + return ret; +} +EXPORT_SYMBOL(iio_sw_probe_trigger); +void iio_sw_remove_trigger(struct iio_dev *indio_dev) +{ + struct iio_state *state =3D indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} +EXPORT_SYMBOL(iio_sw_remove_trigger); name and attribute_group can be params for iio_sw_probe_trigger() since functions depend on them. But set_trigger_state(), try_reenable() can be given chip-special entries in bottom driver after iio_sw_probe_trigger() returns successfully. >>> >>> As an aside. There is an awful lot of repeated code relating to low lev= el >>> device access in the adis drivers. Perhaps that is a good opportunity f= or >>> unifying code? =C2=A0Maybe we want and adis_library module? Or perhaps = a number >>> of the devices can be combined into a single driver? Just a thought >>> that came up whilst looking at that code again. >> >> Good idea in fact. Many codes are same, for example spi read. But it >> is really difficult to find the orderliness to build a library for the >> moment. > One for a later round of clean ups! =C2=A0Perhaps I'll take a look at how > easy this would be to do. > > Jonathan > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Uclinux-dist-devel] IIO ring buffer 2010-07-08 10:38 ` Barry Song @ 2010-07-08 15:04 ` Jonathan Cameron 0 siblings, 0 replies; 31+ messages in thread From: Jonathan Cameron @ 2010-07-08 15:04 UTC (permalink / raw) To: Barry Song Cc: Song, Barry, linux-iio, uclinux-dist-devel, manuel.stahl, jic23 <snip> >>>> The rest of your factoring out obviously requires the shared driver >>>> state structure. This all makes sense if we think that is a desirable >>>> thing to do. >>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev) >>>>> +{ >>>>> + int ret; >>>>> + struct iio_state *st = indio_dev->dev_data; >>>>> + >>>>> + st->trig = iio_allocate_trigger(); >>>>> + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); >>>>> + if (!st->trig->name) { >>>>> + ret = -ENOMEM; >>>>> + goto error_free_trig; >>>>> + } >>>>> + snprintf((char *)st->trig->name, >>>>> + IIO_TRIGGER_NAME_LENGTH, >>>>> + "iio-dev%d", indio_dev->id); >>>>> + st->trig->dev.parent = st->parent_dev; >>>>> + st->trig->owner = THIS_MODULE; >>>>> + st->trig->private_data = st; >>>>> + st->trig->set_trigger_state = &iio_common_trigger_set_state; >>>>> + st->trig->try_reenable = &iio_common_trigger_try_reen; >>>>> + st->trig->control_attrs = &iio_trigger_attr_group; >>>>> + ret = iio_trigger_register(st->trig); >>>>> + >>>>> + /* select default trigger */ >>>>> + indio_dev->trig = st->trig; >>>>> + if (ret) >>>>> + goto error_free_trig_name; >>>>> + >>>>> + return 0; >>>>> + >>>>> +error_free_trig_name: >>>>> + kfree(st->trig->name); >>>>> +error_free_trig: >>>>> + iio_free_trigger(st->trig); >>>>> + >>>>> + return ret; >>>>> +} >>>>> +EXPORT_SYMBOL(iio_probe_common_trigger); >>>>> + >>>> >>>> >>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev) >>>>> +{ >>>>> + struct iio_state *state = indio_dev->dev_data; >>>>> + >>>>> + iio_trigger_unregister(state->trig); >>>>> + kfree(state->trig->name); >>>>> + iio_free_trigger(state->trig); >>>>> +} >>>>> +EXPORT_SYMBOL(iio_remove_common_trigger); >>>> >>>> snipped rest as it is obvious boiler pate. > > For this, how about we let bottom driver to implement > set_trigger_state(), try_reenable(), and control_attrs of trigger, but > probe() and remove() can be common like this: > > drivers/staging/iio/ring_sw.h > > struct iio_sw_ring_helper_state { > struct work_struct work_trigger_to_ring; > struct iio_dev *indio_dev; I'm not sure this wants to be in this struct. The trigger and ring are intended to be (more or less) completely separable. If we do this, then we immediately cannot use this code with devices not supplying a trigger, or those that are supplying several different ones. Again, you have highlighted an area with a lot of shared code, but perhaps some care is needed to maximise the gain without restricting the generality of the code. > + struct iio_trigger *trig; > int (*get_ring_element)(struct iio_sw_ring_helper_state *st, u8 *buf); > s64 last_timestamp; > }; > > drivers/staging/iio/ring_sw.c > > +int iio_sw_probe_trigger(struct iio_dev *indio_dev, char *name, > struct attribute_group *attr_group) > +{ > + int ret; > + struct iio_sw_ring_helper_state *st = (struct > iio_sw_ring_helper_state *)indio_dev->dev_data; > Perhaps we can give iio_allocate_trigger some parameters and effectively move much of this shared functionality in there? The tricky bit is the name, as it has different conventions for the triggers that are not coming from devices (e.g. gpio)... > + st->trig = iio_allocate_trigger(); Aside: a kasprintf call can clean this next bit up. > + st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); > + if (!st->trig->name) { > + ret = -ENOMEM; > + goto error_free_trig; > + } > + snprintf((char *)st->trig->name, > + IIO_TRIGGER_NAME_LENGTH, > + "%s%d", name, indio_dev->id); > + st->trig->dev.parent = st->parent_dev; > + st->trig->owner = THIS_MODULE; The owner bit just went wrong if we do this as it is no longer the device driver module. > + st->trig->private_data = st; > + st->trig->control_attrs = attr_group; > + ret = iio_trigger_register(st->trig); > > + indio_dev->trig = st->trig; > + if (ret) > + goto error_free_trig_name; > > + return 0; > > +error_free_trig_name: > kfree(st->trig->name); > +error_free_trig: > + iio_free_trigger(st->trig); > > + return ret; > +} > +EXPORT_SYMBOL(iio_sw_probe_trigger); > > +void iio_sw_remove_trigger(struct iio_dev *indio_dev) > +{ > + struct iio_state *state = indio_dev->dev_data; > + > + iio_trigger_unregister(state->trig); > + kfree(state->trig->name); > + iio_free_trigger(state->trig); > +} > +EXPORT_SYMBOL(iio_sw_remove_trigger); > > name and attribute_group can be params for iio_sw_probe_trigger() > since functions depend on them. But set_trigger_state(), > try_reenable() can be given chip-special entries in bottom driver > after iio_sw_probe_trigger() returns successfully. > Can we hold off on doing anything major in here for now. I'd like to see a few more drivers doing event handling as well as triggers as they quite often interact to a degree and may well complicate things with unifying the trigger code. (not sure yet!) <snip> Thanks for looking at all the other patches. I'll send those off to Greg shortly. Jonathan ^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2010-07-08 15:04 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <0F1B54C89D5F954D8535DB252AF412FA05A222FC@chinexm1.ad.analog.com>
2010-02-22 11:16 ` IIO ring buffer Jonathan Cameron
2010-02-23 4:11 ` Song, Barry
2010-02-23 11:44 ` Jonathan Cameron
2010-02-24 6:42 ` Song, Barry
2010-02-24 6:48 ` [Uclinux-dist-devel] " Song, Barry
2010-02-24 14:10 ` Jonathan Cameron
2010-03-02 9:57 ` Barry Song
2010-03-02 10:45 ` J.I. Cameron
2010-03-03 3:26 ` Barry Song
2010-03-03 5:59 ` [Uclinux-dist-devel] " Zhang, Sonic
2010-03-04 12:33 ` Jonathan Cameron
2010-03-08 3:41 ` Barry Song
2010-03-08 11:23 ` Jonathan Cameron
2010-06-02 8:01 ` [Uclinux-dist-devel] " Barry Song
2010-06-02 13:21 ` Jonathan Cameron
2010-06-10 4:48 ` Barry Song
2010-06-10 4:51 ` Barry Song
2010-06-10 13:48 ` Jonathan Cameron
2010-06-11 3:19 ` Barry Song
2010-06-11 10:22 ` Jonathan Cameron
2010-06-12 2:26 ` Barry Song
2010-06-12 17:35 ` Jonathan Cameron
2010-06-21 9:21 ` Barry Song
2010-06-25 14:11 ` Jonathan Cameron
2010-06-25 17:18 ` Jonathan Cameron
2010-06-28 7:59 ` Barry Song
2010-06-28 10:26 ` Jonathan Cameron
2010-06-30 7:51 ` Barry Song
2010-06-30 14:30 ` Jonathan Cameron
2010-07-08 10:38 ` Barry Song
2010-07-08 15:04 ` Jonathan Cameron
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox