Commit 8d98c5cd41d1932bb76a3945b4e8dea889224d87
Committed by
Linus Torvalds
1 parent
2554bd2a68
Exists in
master
and in
7 other branches
[PATCH] ieee1394: single buffer fixes to video1394
Apply and fixup patch from Markus Tavenrath <speedygoo@speedygoo.de> for video1394 to allow only a single buffer on receive and two buffers on transmit. Tested with libdc1394 and dvconnect (libdv). Signed-off-by: Dan Dennedy <dan@dennedy.org> Signed-off-by: Jody McIntyre <scjody@steamballoon.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 85 additions and 25 deletions Side-by-side Diff
drivers/ieee1394/video1394.c
... | ... | @@ -35,6 +35,11 @@ |
35 | 35 | * |
36 | 36 | */ |
37 | 37 | |
38 | +/* Markus Tavenrath <speedygoo@speedygoo.de> : | |
39 | + - fixed checks for valid buffer-numbers in video1394_icotl | |
40 | + - changed the ways the dma prg's are used, now it's possible to use | |
41 | + even a single dma buffer | |
42 | +*/ | |
38 | 43 | #include <linux/config.h> |
39 | 44 | #include <linux/kernel.h> |
40 | 45 | #include <linux/list.h> |
... | ... | @@ -112,6 +117,7 @@ |
112 | 117 | struct it_dma_prg **it_prg; |
113 | 118 | |
114 | 119 | unsigned int *buffer_status; |
120 | + unsigned int *buffer_prg_assignment; | |
115 | 121 | struct timeval *buffer_time; /* time when the buffer was received */ |
116 | 122 | unsigned int *last_used_cmd; /* For ISO Transmit with |
117 | 123 | variable sized packets only ! */ |
... | ... | @@ -183,6 +189,7 @@ |
183 | 189 | kfree(d->ir_prg); |
184 | 190 | kfree(d->it_prg); |
185 | 191 | kfree(d->buffer_status); |
192 | + kfree(d->buffer_prg_assignment); | |
186 | 193 | kfree(d->buffer_time); |
187 | 194 | kfree(d->last_used_cmd); |
188 | 195 | kfree(d->next_buffer); |
... | ... | @@ -220,7 +227,7 @@ |
220 | 227 | /* Init the regions for easy cleanup */ |
221 | 228 | dma_region_init(&d->dma); |
222 | 229 | |
223 | - if (dma_region_alloc(&d->dma, d->num_desc * d->buf_size, ohci->dev, | |
230 | + if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev, | |
224 | 231 | PCI_DMA_BIDIRECTIONAL)) { |
225 | 232 | PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer"); |
226 | 233 | free_dma_iso_ctx(d); |
... | ... | @@ -332,6 +339,8 @@ |
332 | 339 | |
333 | 340 | d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), |
334 | 341 | GFP_KERNEL); |
342 | + d->buffer_prg_assignment = kmalloc(d->num_desc * sizeof(unsigned int), | |
343 | + GFP_KERNEL); | |
335 | 344 | d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval), |
336 | 345 | GFP_KERNEL); |
337 | 346 | d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int), |
... | ... | @@ -344,6 +353,11 @@ |
344 | 353 | free_dma_iso_ctx(d); |
345 | 354 | return NULL; |
346 | 355 | } |
356 | + if (d->buffer_prg_assignment == NULL) { | |
357 | + PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_prg_assignment"); | |
358 | + free_dma_iso_ctx(d); | |
359 | + return NULL; | |
360 | + } | |
347 | 361 | if (d->buffer_time == NULL) { |
348 | 362 | PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_time"); |
349 | 363 | free_dma_iso_ctx(d); |
... | ... | @@ -360,6 +374,7 @@ |
360 | 374 | return NULL; |
361 | 375 | } |
362 | 376 | memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); |
377 | + memset(d->buffer_prg_assignment, 0, d->num_desc * sizeof(unsigned int)); | |
363 | 378 | memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval)); |
364 | 379 | memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int)); |
365 | 380 | memset(d->next_buffer, -1, d->num_desc * sizeof(int)); |
... | ... | @@ -369,7 +384,7 @@ |
369 | 384 | PRINT(KERN_INFO, ohci->host->id, "Iso %s DMA: %d buffers " |
370 | 385 | "of size %d allocated for a frame size %d, each with %d prgs", |
371 | 386 | (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", |
372 | - d->num_desc, d->buf_size, d->frame_size, d->nb_cmd); | |
387 | + d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd); | |
373 | 388 | |
374 | 389 | return d; |
375 | 390 | } |
376 | 391 | |
... | ... | @@ -384,11 +399,36 @@ |
384 | 399 | d->ir_prg[n][i].status = cpu_to_le32(d->left_size); |
385 | 400 | } |
386 | 401 | |
402 | +static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags) | |
403 | +{ | |
404 | + struct dma_cmd *ir_prg = d->ir_prg[n]; | |
405 | + unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; | |
406 | + int i; | |
407 | + | |
408 | + d->buffer_prg_assignment[n] = buffer; | |
409 | + | |
410 | + ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - | |
411 | + (unsigned long)d->dma.kvirt)); | |
412 | + ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, | |
413 | + (buf + 4) - (unsigned long)d->dma.kvirt)); | |
414 | + | |
415 | + for (i=2;i<d->nb_cmd-1;i++) { | |
416 | + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, | |
417 | + (buf+(i-1)*PAGE_SIZE) - | |
418 | + (unsigned long)d->dma.kvirt)); | |
419 | + } | |
420 | + | |
421 | + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | | |
422 | + DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); | |
423 | + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, | |
424 | + (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt)); | |
425 | +} | |
426 | + | |
387 | 427 | static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) |
388 | 428 | { |
389 | 429 | struct dma_cmd *ir_prg = d->ir_prg[n]; |
390 | 430 | struct dma_prog_region *ir_reg = &d->prg_reg[n]; |
391 | - unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; | |
431 | + unsigned long buf = (unsigned long)d->dma.kvirt; | |
392 | 432 | int i; |
393 | 433 | |
394 | 434 | /* the first descriptor will read only 4 bytes */ |
... | ... | @@ -498,7 +538,7 @@ |
498 | 538 | for (i = 0; i < d->num_desc; i++) { |
499 | 539 | if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { |
500 | 540 | reset_ir_status(d, i); |
501 | - d->buffer_status[i] = VIDEO1394_BUFFER_READY; | |
541 | + d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; | |
502 | 542 | do_gettimeofday(&d->buffer_time[i]); |
503 | 543 | } |
504 | 544 | } |
... | ... | @@ -575,7 +615,7 @@ |
575 | 615 | int next = d->next_buffer[i]; |
576 | 616 | put_timestamp(ohci, d, next); |
577 | 617 | d->it_prg[i][d->last_used_cmd[i]].end.status = 0; |
578 | - d->buffer_status[i] = VIDEO1394_BUFFER_READY; | |
618 | + d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; | |
579 | 619 | } |
580 | 620 | } |
581 | 621 | |
582 | 622 | |
... | ... | @@ -585,11 +625,25 @@ |
585 | 625 | wake_up_interruptible(&d->waitq); |
586 | 626 | } |
587 | 627 | |
628 | +static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer) | |
629 | +{ | |
630 | + struct it_dma_prg *it_prg = d->it_prg[n]; | |
631 | + unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; | |
632 | + int i; | |
633 | + | |
634 | + d->buffer_prg_assignment[n] = buffer; | |
635 | + for (i=0;i<d->nb_cmd;i++) { | |
636 | + it_prg[i].end.address = | |
637 | + cpu_to_le32(dma_region_offset_to_bus(&d->dma, | |
638 | + (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt)); | |
639 | + } | |
640 | +} | |
641 | + | |
588 | 642 | static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) |
589 | 643 | { |
590 | 644 | struct it_dma_prg *it_prg = d->it_prg[n]; |
591 | 645 | struct dma_prog_region *it_reg = &d->prg_reg[n]; |
592 | - unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; | |
646 | + unsigned long buf = (unsigned long)d->dma.kvirt; | |
593 | 647 | int i; |
594 | 648 | d->last_used_cmd[n] = d->nb_cmd - 1; |
595 | 649 | for (i=0;i<d->nb_cmd;i++) { |
... | ... | @@ -786,7 +840,7 @@ |
786 | 840 | |
787 | 841 | if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) { |
788 | 842 | d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE, |
789 | - v.nb_buffers, v.buf_size, | |
843 | + v.nb_buffers + 1, v.buf_size, | |
790 | 844 | v.channel, 0); |
791 | 845 | |
792 | 846 | if (d == NULL) { |
... | ... | @@ -807,7 +861,7 @@ |
807 | 861 | } |
808 | 862 | else { |
809 | 863 | d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT, |
810 | - v.nb_buffers, v.buf_size, | |
864 | + v.nb_buffers + 1, v.buf_size, | |
811 | 865 | v.channel, v.packet_size); |
812 | 866 | |
813 | 867 | if (d == NULL) { |
... | ... | @@ -879,6 +933,7 @@ |
879 | 933 | { |
880 | 934 | struct video1394_wait v; |
881 | 935 | struct dma_iso_ctx *d; |
936 | + int next_prg; | |
882 | 937 | |
883 | 938 | if (copy_from_user(&v, argp, sizeof(v))) |
884 | 939 | return -EFAULT; |
... | ... | @@ -886,7 +941,7 @@ |
886 | 941 | d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); |
887 | 942 | if (d == NULL) return -EFAULT; |
888 | 943 | |
889 | - if ((v.buffer<0) || (v.buffer>d->num_desc)) { | |
944 | + if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { | |
890 | 945 | PRINT(KERN_ERR, ohci->host->id, |
891 | 946 | "Buffer %d out of range",v.buffer); |
892 | 947 | return -EINVAL; |
893 | 948 | |
894 | 949 | |
... | ... | @@ -903,12 +958,14 @@ |
903 | 958 | |
904 | 959 | d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; |
905 | 960 | |
961 | + next_prg = (d->last_buffer + 1) % d->num_desc; | |
906 | 962 | if (d->last_buffer>=0) |
907 | 963 | d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = |
908 | - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | |
964 | + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | |
909 | 965 | & 0xfffffff0) | 0x1); |
910 | 966 | |
911 | - d->last_buffer = v.buffer; | |
967 | + d->last_buffer = next_prg; | |
968 | + reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags); | |
912 | 969 | |
913 | 970 | d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0; |
914 | 971 | |
... | ... | @@ -920,7 +977,7 @@ |
920 | 977 | |
921 | 978 | /* Tell the controller where the first program is */ |
922 | 979 | reg_write(ohci, d->cmdPtr, |
923 | - dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1); | |
980 | + dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1); | |
924 | 981 | |
925 | 982 | /* Run IR context */ |
926 | 983 | reg_write(ohci, d->ctrlSet, 0x8000); |
... | ... | @@ -941,7 +998,7 @@ |
941 | 998 | { |
942 | 999 | struct video1394_wait v; |
943 | 1000 | struct dma_iso_ctx *d; |
944 | - int i; | |
1001 | + int i = 0; | |
945 | 1002 | |
946 | 1003 | if (copy_from_user(&v, argp, sizeof(v))) |
947 | 1004 | return -EFAULT; |
... | ... | @@ -949,7 +1006,7 @@ |
949 | 1006 | d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); |
950 | 1007 | if (d == NULL) return -EFAULT; |
951 | 1008 | |
952 | - if ((v.buffer<0) || (v.buffer>d->num_desc)) { | |
1009 | + if ((v.buffer<0) || (v.buffer>d->num_desc - 1)) { | |
953 | 1010 | PRINT(KERN_ERR, ohci->host->id, |
954 | 1011 | "Buffer %d out of range",v.buffer); |
955 | 1012 | return -EINVAL; |
956 | 1013 | |
... | ... | @@ -995,9 +1052,9 @@ |
995 | 1052 | * Look ahead to see how many more buffers have been received |
996 | 1053 | */ |
997 | 1054 | i=0; |
998 | - while (d->buffer_status[(v.buffer+1)%d->num_desc]== | |
1055 | + while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]== | |
999 | 1056 | VIDEO1394_BUFFER_READY) { |
1000 | - v.buffer=(v.buffer+1)%d->num_desc; | |
1057 | + v.buffer=(v.buffer+1)%(d->num_desc - 1); | |
1001 | 1058 | i++; |
1002 | 1059 | } |
1003 | 1060 | spin_unlock_irqrestore(&d->lock, flags); |
... | ... | @@ -1013,6 +1070,7 @@ |
1013 | 1070 | struct video1394_wait v; |
1014 | 1071 | unsigned int *psizes = NULL; |
1015 | 1072 | struct dma_iso_ctx *d; |
1073 | + int next_prg; | |
1016 | 1074 | |
1017 | 1075 | if (copy_from_user(&v, argp, sizeof(v))) |
1018 | 1076 | return -EFAULT; |
... | ... | @@ -1020,7 +1078,7 @@ |
1020 | 1078 | d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); |
1021 | 1079 | if (d == NULL) return -EFAULT; |
1022 | 1080 | |
1023 | - if ((v.buffer<0) || (v.buffer>d->num_desc)) { | |
1081 | + if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { | |
1024 | 1082 | PRINT(KERN_ERR, ohci->host->id, |
1025 | 1083 | "Buffer %d out of range",v.buffer); |
1026 | 1084 | return -EINVAL; |
... | ... | @@ -1046,6 +1104,8 @@ |
1046 | 1104 | |
1047 | 1105 | spin_lock_irqsave(&d->lock,flags); |
1048 | 1106 | |
1107 | + // last_buffer is last_prg | |
1108 | + next_prg = (d->last_buffer + 1) % d->num_desc; | |
1049 | 1109 | if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { |
1050 | 1110 | PRINT(KERN_ERR, ohci->host->id, |
1051 | 1111 | "Buffer %d is already used",v.buffer); |
... | ... | @@ -1056,8 +1116,7 @@ |
1056 | 1116 | |
1057 | 1117 | if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { |
1058 | 1118 | initialize_dma_it_prg_var_packet_queue( |
1059 | - d, v.buffer, psizes, | |
1060 | - ohci); | |
1119 | + d, next_prg, psizes, ohci); | |
1061 | 1120 | } |
1062 | 1121 | |
1063 | 1122 | d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; |
1064 | 1123 | |
1065 | 1124 | |
1066 | 1125 | |
... | ... | @@ -1065,16 +1124,17 @@ |
1065 | 1124 | if (d->last_buffer >= 0) { |
1066 | 1125 | d->it_prg[d->last_buffer] |
1067 | 1126 | [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = |
1068 | - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], | |
1127 | + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], | |
1069 | 1128 | 0) & 0xfffffff0) | 0x3); |
1070 | 1129 | |
1071 | 1130 | d->it_prg[d->last_buffer] |
1072 | 1131 | [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress = |
1073 | - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], | |
1132 | + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], | |
1074 | 1133 | 0) & 0xfffffff0) | 0x3); |
1075 | - d->next_buffer[d->last_buffer] = v.buffer; | |
1134 | + d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1); | |
1076 | 1135 | } |
1077 | - d->last_buffer = v.buffer; | |
1136 | + d->last_buffer = next_prg; | |
1137 | + reprogram_dma_it_prg(d, d->last_buffer, v.buffer); | |
1078 | 1138 | d->next_buffer[d->last_buffer] = -1; |
1079 | 1139 | |
1080 | 1140 | d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0; |
... | ... | @@ -1089,7 +1149,7 @@ |
1089 | 1149 | |
1090 | 1150 | /* Tell the controller where the first program is */ |
1091 | 1151 | reg_write(ohci, d->cmdPtr, |
1092 | - dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3); | |
1152 | + dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3); | |
1093 | 1153 | |
1094 | 1154 | /* Run IT context */ |
1095 | 1155 | reg_write(ohci, d->ctrlSet, 0x8000); |
... | ... | @@ -1120,7 +1180,7 @@ |
1120 | 1180 | d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); |
1121 | 1181 | if (d == NULL) return -EFAULT; |
1122 | 1182 | |
1123 | - if ((v.buffer<0) || (v.buffer>d->num_desc)) { | |
1183 | + if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) { | |
1124 | 1184 | PRINT(KERN_ERR, ohci->host->id, |
1125 | 1185 | "Buffer %d out of range",v.buffer); |
1126 | 1186 | return -EINVAL; |