diff options
author | Vijay Kumar B <vijaykumar@bravegnu.org> | 2009-09-21 11:23:55 +0530 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 12:23:09 -0800 |
commit | b01faf05740884f915dd1b8652d8af1b6f458ccc (patch) | |
tree | b6671d121618dbf9c20efe8c1b9e9ed7f6f56f08 /drivers/staging/poch/poch.c | |
parent | 16fbf4cba0880c31445d6414abbd7a1c51466b1f (diff) |
Staging: poch: Fetch Flush IOCTL interface
Change user space interface to an IOCTL based interface instead of a
memory mapped circular buffer. The circular buffer had some serious
cache(?) issues and never worked.
Signed-off-by: Vijay Kumar B. <vijaykumar@bravegnu.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/poch/poch.c')
-rw-r--r-- | drivers/staging/poch/poch.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/drivers/staging/poch/poch.c b/drivers/staging/poch/poch.c index 1308c7bada8a..6b4aa5f1d51d 100644 --- a/drivers/staging/poch/poch.c +++ b/drivers/staging/poch/poch.c @@ -201,6 +201,8 @@ struct channel_info { struct page *header_pg; unsigned long header_size; + /* Last group consumed by user space. */ + unsigned int consumed; /* Last group indicated as 'complete' to user space. */ unsigned int transfer; @@ -589,6 +591,7 @@ static int poch_channel_init(struct channel_info *channel, if (ret != 0) goto out; + channel->consumed = 0; channel->transfer = 0; /* Allocate memory to hold group information. */ @@ -1033,6 +1036,51 @@ static int poch_ioctl(struct inode *inode, struct file *filp, break; } break; + case POCH_IOC_CONSUME: + { + int available; + int nfetch; + unsigned int from; + unsigned int count; + unsigned int i, j; + struct poch_consume consume; + struct poch_consume *uconsume; + + uconsume = argp; + ret = copy_from_user(&consume, uconsume, sizeof(consume)); + if (ret) + return ret; + + spin_lock_irq(&channel->group_offsets_lock); + + channel->consumed += consume.nflush; + channel->consumed %= channel->group_count; + + available = channel->transfer - channel->consumed; + if (available < 0) + available += channel->group_count; + + from = channel->consumed; + + spin_unlock_irq(&channel->group_offsets_lock); + + nfetch = consume.nfetch; + count = min(available, nfetch); + + for (i = 0; i < count; i++) { + j = (from + i) % channel->group_count; + ret = put_user(channel->groups[j].user_offset, + &consume.offsets[i]); + if (ret) + return -EFAULT; + } + + ret = put_user(count, &uconsume->nfetch); + if (ret) + return -EFAULT; + + break; + } case POCH_IOC_GET_COUNTERS: if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) return -EFAULT; @@ -1108,12 +1156,18 @@ static void poch_irq_dma(struct channel_info *channel) for (i = 0; i < groups_done; i++) { j = (prev_transfer + i) % channel->group_count; group_offsets[j] = groups[j].user_offset; + + channel->transfer += 1; + channel->transfer %= channel->group_count; + + if (channel->transfer == channel->consumed) { + channel->consumed += 1; + channel->consumed %= channel->group_count; + } } spin_unlock(&channel->group_offsets_lock); - channel->transfer = curr_transfer; - wake_up_interruptible(&channel->wq); } |