diff options
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 1308c7bada8..6b4aa5f1d51 100644 --- a/drivers/staging/poch/poch.c +++ b/drivers/staging/poch/poch.c | |||
@@ -201,6 +201,8 @@ struct channel_info { | |||
201 | struct page *header_pg; | 201 | struct page *header_pg; |
202 | unsigned long header_size; | 202 | unsigned long header_size; |
203 | 203 | ||
204 | /* Last group consumed by user space. */ | ||
205 | unsigned int consumed; | ||
204 | /* Last group indicated as 'complete' to user space. */ | 206 | /* Last group indicated as 'complete' to user space. */ |
205 | unsigned int transfer; | 207 | unsigned int transfer; |
206 | 208 | ||
@@ -589,6 +591,7 @@ static int poch_channel_init(struct channel_info *channel, | |||
589 | if (ret != 0) | 591 | if (ret != 0) |
590 | goto out; | 592 | goto out; |
591 | 593 | ||
594 | channel->consumed = 0; | ||
592 | channel->transfer = 0; | 595 | channel->transfer = 0; |
593 | 596 | ||
594 | /* Allocate memory to hold group information. */ | 597 | /* Allocate memory to hold group information. */ |
@@ -1033,6 +1036,51 @@ static int poch_ioctl(struct inode *inode, struct file *filp, | |||
1033 | break; | 1036 | break; |
1034 | } | 1037 | } |
1035 | break; | 1038 | break; |
1039 | case POCH_IOC_CONSUME: | ||
1040 | { | ||
1041 | int available; | ||
1042 | int nfetch; | ||
1043 | unsigned int from; | ||
1044 | unsigned int count; | ||
1045 | unsigned int i, j; | ||
1046 | struct poch_consume consume; | ||
1047 | struct poch_consume *uconsume; | ||
1048 | |||
1049 | uconsume = argp; | ||
1050 | ret = copy_from_user(&consume, uconsume, sizeof(consume)); | ||
1051 | if (ret) | ||
1052 | return ret; | ||
1053 | |||
1054 | spin_lock_irq(&channel->group_offsets_lock); | ||
1055 | |||
1056 | channel->consumed += consume.nflush; | ||
1057 | channel->consumed %= channel->group_count; | ||
1058 | |||
1059 | available = channel->transfer - channel->consumed; | ||
1060 | if (available < 0) | ||
1061 | available += channel->group_count; | ||
1062 | |||
1063 | from = channel->consumed; | ||
1064 | |||
1065 | spin_unlock_irq(&channel->group_offsets_lock); | ||
1066 | |||
1067 | nfetch = consume.nfetch; | ||
1068 | count = min(available, nfetch); | ||
1069 | |||
1070 | for (i = 0; i < count; i++) { | ||
1071 | j = (from + i) % channel->group_count; | ||
1072 | ret = put_user(channel->groups[j].user_offset, | ||
1073 | &consume.offsets[i]); | ||
1074 | if (ret) | ||
1075 | return -EFAULT; | ||
1076 | } | ||
1077 | |||
1078 | ret = put_user(count, &uconsume->nfetch); | ||
1079 | if (ret) | ||
1080 | return -EFAULT; | ||
1081 | |||
1082 | break; | ||
1083 | } | ||
1036 | case POCH_IOC_GET_COUNTERS: | 1084 | case POCH_IOC_GET_COUNTERS: |
1037 | if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) | 1085 | if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) |
1038 | return -EFAULT; | 1086 | return -EFAULT; |
@@ -1108,12 +1156,18 @@ static void poch_irq_dma(struct channel_info *channel) | |||
1108 | for (i = 0; i < groups_done; i++) { | 1156 | for (i = 0; i < groups_done; i++) { |
1109 | j = (prev_transfer + i) % channel->group_count; | 1157 | j = (prev_transfer + i) % channel->group_count; |
1110 | group_offsets[j] = groups[j].user_offset; | 1158 | group_offsets[j] = groups[j].user_offset; |
1159 | |||
1160 | channel->transfer += 1; | ||
1161 | channel->transfer %= channel->group_count; | ||
1162 | |||
1163 | if (channel->transfer == channel->consumed) { | ||
1164 | channel->consumed += 1; | ||
1165 | channel->consumed %= channel->group_count; | ||
1166 | } | ||
1111 | } | 1167 | } |
1112 | 1168 | ||
1113 | spin_unlock(&channel->group_offsets_lock); | 1169 | spin_unlock(&channel->group_offsets_lock); |
1114 | 1170 | ||
1115 | channel->transfer = curr_transfer; | ||
1116 | |||
1117 | wake_up_interruptible(&channel->wq); | 1171 | wake_up_interruptible(&channel->wq); |
1118 | } | 1172 | } |
1119 | 1173 | ||