0001
0002
0003
0004
0005
0006
0007 #include "pvrusb2-ioread.h"
0008 #include "pvrusb2-debug.h"
0009 #include <linux/errno.h>
0010 #include <linux/string.h>
0011 #include <linux/mm.h>
0012 #include <linux/slab.h>
0013 #include <linux/mutex.h>
0014 #include <linux/uaccess.h>
0015
0016 #define BUFFER_COUNT 32
0017 #define BUFFER_SIZE PAGE_ALIGN(0x4000)
0018
0019 struct pvr2_ioread {
0020 struct pvr2_stream *stream;
0021 char *buffer_storage[BUFFER_COUNT];
0022 char *sync_key_ptr;
0023 unsigned int sync_key_len;
0024 unsigned int sync_buf_offs;
0025 unsigned int sync_state;
0026 unsigned int sync_trashed_count;
0027 int enabled;
0028 int spigot_open;
0029 int stream_running;
0030
0031
0032 struct pvr2_buffer *c_buf;
0033 char *c_data_ptr;
0034 unsigned int c_data_len;
0035 unsigned int c_data_offs;
0036 struct mutex mutex;
0037 };
0038
0039 static int pvr2_ioread_init(struct pvr2_ioread *cp)
0040 {
0041 unsigned int idx;
0042
0043 cp->stream = NULL;
0044 mutex_init(&cp->mutex);
0045
0046 for (idx = 0; idx < BUFFER_COUNT; idx++) {
0047 cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
0048 if (!(cp->buffer_storage[idx])) break;
0049 }
0050
0051 if (idx < BUFFER_COUNT) {
0052
0053 for (idx = 0; idx < BUFFER_COUNT; idx++) {
0054 if (!(cp->buffer_storage[idx])) continue;
0055 kfree(cp->buffer_storage[idx]);
0056 }
0057 return -ENOMEM;
0058 }
0059 return 0;
0060 }
0061
0062 static void pvr2_ioread_done(struct pvr2_ioread *cp)
0063 {
0064 unsigned int idx;
0065
0066 pvr2_ioread_setup(cp,NULL);
0067 for (idx = 0; idx < BUFFER_COUNT; idx++) {
0068 if (!(cp->buffer_storage[idx])) continue;
0069 kfree(cp->buffer_storage[idx]);
0070 }
0071 }
0072
0073 struct pvr2_ioread *pvr2_ioread_create(void)
0074 {
0075 struct pvr2_ioread *cp;
0076 cp = kzalloc(sizeof(*cp),GFP_KERNEL);
0077 if (!cp) return NULL;
0078 pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
0079 if (pvr2_ioread_init(cp) < 0) {
0080 kfree(cp);
0081 return NULL;
0082 }
0083 return cp;
0084 }
0085
0086 void pvr2_ioread_destroy(struct pvr2_ioread *cp)
0087 {
0088 if (!cp) return;
0089 pvr2_ioread_done(cp);
0090 pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
0091 if (cp->sync_key_ptr) {
0092 kfree(cp->sync_key_ptr);
0093 cp->sync_key_ptr = NULL;
0094 }
0095 kfree(cp);
0096 }
0097
0098 void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
0099 const char *sync_key_ptr,
0100 unsigned int sync_key_len)
0101 {
0102 if (!cp) return;
0103
0104 if (!sync_key_ptr) sync_key_len = 0;
0105 if ((sync_key_len == cp->sync_key_len) &&
0106 ((!sync_key_len) ||
0107 (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
0108
0109 if (sync_key_len != cp->sync_key_len) {
0110 if (cp->sync_key_ptr) {
0111 kfree(cp->sync_key_ptr);
0112 cp->sync_key_ptr = NULL;
0113 }
0114 cp->sync_key_len = 0;
0115 if (sync_key_len) {
0116 cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
0117 if (cp->sync_key_ptr) {
0118 cp->sync_key_len = sync_key_len;
0119 }
0120 }
0121 }
0122 if (!cp->sync_key_len) return;
0123 memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
0124 }
0125
0126 static void pvr2_ioread_stop(struct pvr2_ioread *cp)
0127 {
0128 if (!(cp->enabled)) return;
0129 pvr2_trace(PVR2_TRACE_START_STOP,
0130 "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
0131 pvr2_stream_kill(cp->stream);
0132 cp->c_buf = NULL;
0133 cp->c_data_ptr = NULL;
0134 cp->c_data_len = 0;
0135 cp->c_data_offs = 0;
0136 cp->enabled = 0;
0137 cp->stream_running = 0;
0138 cp->spigot_open = 0;
0139 if (cp->sync_state) {
0140 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0141 "/*---TRACE_READ---*/ sync_state <== 0");
0142 cp->sync_state = 0;
0143 }
0144 }
0145
0146 static int pvr2_ioread_start(struct pvr2_ioread *cp)
0147 {
0148 int stat;
0149 struct pvr2_buffer *bp;
0150 if (cp->enabled) return 0;
0151 if (!(cp->stream)) return 0;
0152 pvr2_trace(PVR2_TRACE_START_STOP,
0153 "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
0154 while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
0155 stat = pvr2_buffer_queue(bp);
0156 if (stat < 0) {
0157 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0158 "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
0159 cp,stat);
0160 pvr2_ioread_stop(cp);
0161 return stat;
0162 }
0163 }
0164 cp->enabled = !0;
0165 cp->c_buf = NULL;
0166 cp->c_data_ptr = NULL;
0167 cp->c_data_len = 0;
0168 cp->c_data_offs = 0;
0169 cp->stream_running = 0;
0170 if (cp->sync_key_len) {
0171 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0172 "/*---TRACE_READ---*/ sync_state <== 1");
0173 cp->sync_state = 1;
0174 cp->sync_trashed_count = 0;
0175 cp->sync_buf_offs = 0;
0176 }
0177 cp->spigot_open = 0;
0178 return 0;
0179 }
0180
0181 struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
0182 {
0183 return cp->stream;
0184 }
0185
0186 int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
0187 {
0188 int ret;
0189 unsigned int idx;
0190 struct pvr2_buffer *bp;
0191
0192 mutex_lock(&cp->mutex);
0193 do {
0194 if (cp->stream) {
0195 pvr2_trace(PVR2_TRACE_START_STOP,
0196 "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
0197 cp);
0198 pvr2_ioread_stop(cp);
0199 pvr2_stream_kill(cp->stream);
0200 if (pvr2_stream_get_buffer_count(cp->stream)) {
0201 pvr2_stream_set_buffer_count(cp->stream,0);
0202 }
0203 cp->stream = NULL;
0204 }
0205 if (sp) {
0206 pvr2_trace(PVR2_TRACE_START_STOP,
0207 "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
0208 cp);
0209 pvr2_stream_kill(sp);
0210 ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
0211 if (ret < 0) {
0212 mutex_unlock(&cp->mutex);
0213 return ret;
0214 }
0215 for (idx = 0; idx < BUFFER_COUNT; idx++) {
0216 bp = pvr2_stream_get_buffer(sp,idx);
0217 pvr2_buffer_set_buffer(bp,
0218 cp->buffer_storage[idx],
0219 BUFFER_SIZE);
0220 }
0221 cp->stream = sp;
0222 }
0223 } while (0);
0224 mutex_unlock(&cp->mutex);
0225
0226 return 0;
0227 }
0228
0229 int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
0230 {
0231 int ret = 0;
0232 if ((!fl) == (!(cp->enabled))) return ret;
0233
0234 mutex_lock(&cp->mutex);
0235 do {
0236 if (fl) {
0237 ret = pvr2_ioread_start(cp);
0238 } else {
0239 pvr2_ioread_stop(cp);
0240 }
0241 } while (0);
0242 mutex_unlock(&cp->mutex);
0243 return ret;
0244 }
0245
0246 static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
0247 {
0248 int stat;
0249
0250 while (cp->c_data_len <= cp->c_data_offs) {
0251 if (cp->c_buf) {
0252
0253 stat = pvr2_buffer_queue(cp->c_buf);
0254 if (stat < 0) {
0255
0256 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0257 "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
0258 cp,stat);
0259 pvr2_ioread_stop(cp);
0260 return 0;
0261 }
0262 cp->c_buf = NULL;
0263 cp->c_data_ptr = NULL;
0264 cp->c_data_len = 0;
0265 cp->c_data_offs = 0;
0266 }
0267
0268 cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
0269 if (!cp->c_buf) break;
0270 cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
0271 if (!cp->c_data_len) {
0272
0273 stat = pvr2_buffer_get_status(cp->c_buf);
0274 if (stat < 0) {
0275
0276 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0277 "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
0278 cp,stat);
0279 pvr2_ioread_stop(cp);
0280
0281 return 0;
0282 }
0283
0284 continue;
0285 }
0286 cp->c_data_offs = 0;
0287 cp->c_data_ptr = cp->buffer_storage[
0288 pvr2_buffer_get_id(cp->c_buf)];
0289 }
0290 return !0;
0291 }
0292
0293 static void pvr2_ioread_filter(struct pvr2_ioread *cp)
0294 {
0295 unsigned int idx;
0296 if (!cp->enabled) return;
0297 if (cp->sync_state != 1) return;
0298
0299
0300
0301
0302 mutex_lock(&cp->mutex);
0303 while (1) {
0304
0305 if (!pvr2_ioread_get_buffer(cp)) break;
0306 if (!cp->c_data_len) break;
0307
0308
0309
0310 for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
0311 if (cp->sync_buf_offs >= cp->sync_key_len) break;
0312 if (cp->c_data_ptr[idx] ==
0313 cp->sync_key_ptr[cp->sync_buf_offs]) {
0314
0315 (cp->sync_buf_offs)++;
0316 } else {
0317
0318 cp->sync_buf_offs = 0;
0319 }
0320 }
0321
0322
0323 cp->c_data_offs += idx;
0324 cp->sync_trashed_count += idx;
0325
0326
0327 if (cp->sync_buf_offs >= cp->sync_key_len) {
0328 cp->sync_trashed_count -= cp->sync_key_len;
0329 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0330 "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
0331 cp->sync_trashed_count);
0332 cp->sync_state = 2;
0333 cp->sync_buf_offs = 0;
0334 break;
0335 }
0336
0337 if (cp->c_data_offs < cp->c_data_len) {
0338
0339 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
0340 "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
0341 cp->c_data_len,cp->c_data_offs);
0342
0343
0344 break;
0345 }
0346
0347 continue;
0348 }
0349 mutex_unlock(&cp->mutex);
0350 }
0351
0352 int pvr2_ioread_avail(struct pvr2_ioread *cp)
0353 {
0354 int ret;
0355 if (!(cp->enabled)) {
0356
0357 return -EIO;
0358 }
0359
0360 if (cp->sync_state == 1) {
0361 pvr2_ioread_filter(cp);
0362 if (cp->sync_state == 1) return -EAGAIN;
0363 }
0364
0365 ret = 0;
0366 if (cp->stream_running) {
0367 if (!pvr2_stream_get_ready_count(cp->stream)) {
0368
0369 ret = -EAGAIN;
0370 }
0371 } else {
0372 if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
0373
0374 ret = -EAGAIN;
0375 }
0376 }
0377
0378 if ((!(cp->spigot_open)) != (!(ret == 0))) {
0379 cp->spigot_open = (ret == 0);
0380 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0381 "/*---TRACE_READ---*/ data is %s",
0382 cp->spigot_open ? "available" : "pending");
0383 }
0384
0385 return ret;
0386 }
0387
0388 int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
0389 {
0390 unsigned int copied_cnt;
0391 unsigned int bcnt;
0392 const char *src;
0393 int stat;
0394 int ret = 0;
0395 unsigned int req_cnt = cnt;
0396
0397 if (!cnt) {
0398 pvr2_trace(PVR2_TRACE_TRAP,
0399 "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
0400 cp);
0401 return 0;
0402 }
0403
0404 stat = pvr2_ioread_avail(cp);
0405 if (stat < 0) return stat;
0406
0407 cp->stream_running = !0;
0408
0409 mutex_lock(&cp->mutex);
0410 do {
0411
0412
0413 copied_cnt = 0;
0414 if (!buf) cnt = 0;
0415 while (1) {
0416 if (!pvr2_ioread_get_buffer(cp)) {
0417 ret = -EIO;
0418 break;
0419 }
0420
0421 if (!cnt) break;
0422
0423 if (cp->sync_state == 2) {
0424
0425
0426 src = cp->sync_key_ptr + cp->sync_buf_offs;
0427 bcnt = cp->sync_key_len - cp->sync_buf_offs;
0428 } else {
0429
0430 src = cp->c_data_ptr + cp->c_data_offs;
0431 bcnt = cp->c_data_len - cp->c_data_offs;
0432 }
0433
0434 if (!bcnt) break;
0435
0436
0437 if (bcnt > cnt) bcnt = cnt;
0438
0439 if (copy_to_user(buf,src,bcnt)) {
0440
0441
0442
0443 ret = -EFAULT;
0444 break;
0445 }
0446 cnt -= bcnt;
0447 buf += bcnt;
0448 copied_cnt += bcnt;
0449
0450 if (cp->sync_state == 2) {
0451
0452
0453 cp->sync_buf_offs += bcnt;
0454 if (cp->sync_buf_offs >= cp->sync_key_len) {
0455
0456
0457 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0458 "/*---TRACE_READ---*/ sync_state <== 0");
0459 cp->sync_state = 0;
0460 }
0461 } else {
0462
0463 cp->c_data_offs += bcnt;
0464 }
0465 }
0466
0467 } while (0);
0468 mutex_unlock(&cp->mutex);
0469
0470 if (!ret) {
0471 if (copied_cnt) {
0472
0473 ret = copied_cnt;
0474 } else {
0475
0476
0477 ret = -EAGAIN;
0478 }
0479 }
0480
0481 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0482 "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
0483 cp,req_cnt,ret);
0484 return ret;
0485 }