X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fvideo1394.c;h=f4d1ec00af652372b1ed37a5a5ffa2401e5dc2d8;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=d68c4658f2fc1d11b10efed4f0269e56514bbf95;hpb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;p=linux-2.6.git diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index d68c4658f..f4d1ec00a 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -19,12 +19,6 @@ * * NOTES: * - * jds -- add private data to file to keep track of iso contexts associated - * with each open -- so release won't kill all iso transfers. - * - * Damien Douxchamps: Fix failure when the number of DMA pages per frame is - * one. - * * ioctl return codes: * EFAULT is only for invalid address for the argp * EINVAL for out of range values @@ -34,13 +28,6 @@ * ENOTTY for unsupported ioctl request * */ - -/* Markus Tavenrath : - - fixed checks for valid buffer-numbers in video1394_icotl - - changed the ways the dma prg's are used, now it's possible to use - even a single dma buffer -*/ -#include #include #include #include @@ -54,37 +41,27 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include -#include "ieee1394.h" -#include "ieee1394_types.h" +#include "dma.h" +#include "highlevel.h" #include "hosts.h" +#include "ieee1394.h" #include "ieee1394_core.h" -#include "highlevel.h" -#include "video1394.h" +#include "ieee1394_hotplug.h" +#include "ieee1394_types.h" #include "nodemgr.h" -#include "dma.h" - #include "ohci1394.h" +#include "video1394.h" #define ISO_CHANNELS 64 -#ifndef virt_to_page -#define virt_to_page(x) MAP_NR(x) -#endif - -#ifndef vmalloc_32 -#define vmalloc_32(x) vmalloc(x) -#endif - struct it_dma_prg { struct dma_cmd begin; quadlet_t data[4]; @@ -152,7 +129,7 @@ struct file_ctx { #define DBGMSG(card, fmt, args...) \ printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args) #else -#define DBGMSG(card, fmt, args...) +#define DBGMSG(card, fmt, args...) do {} while (0) #endif /* print general (card independent) information */ @@ -206,14 +183,12 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, struct dma_iso_ctx *d; int i; - d = kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); - if (d == NULL) { + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx"); return NULL; } - memset(d, 0, sizeof *d); - d->ohci = ohci; d->type = type; d->channel = channel; @@ -251,9 +226,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, } d->ctx = d->iso_tasklet.context; - d->prg_reg = kmalloc(d->num_desc * sizeof(struct dma_prog_region), - GFP_KERNEL); - if (d->prg_reg == NULL) { + d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL); + if (!d->prg_reg) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs"); free_dma_iso_ctx(d); return NULL; @@ -268,15 +242,14 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx; d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx; - d->ir_prg = kmalloc(d->num_desc * sizeof(struct dma_cmd *), + d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg), GFP_KERNEL); - if (d->ir_prg == NULL) { + if (!d->ir_prg) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg"); free_dma_iso_ctx(d); return NULL; } - memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *)); d->nb_cmd = d->buf_size / PAGE_SIZE + 1; d->left_size = (d->frame_size % PAGE_SIZE) ? @@ -297,16 +270,15 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; - d->it_prg = kmalloc(d->num_desc * sizeof(struct it_dma_prg *), + d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg), GFP_KERNEL); - if (d->it_prg == NULL) { + if (!d->it_prg) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg"); free_dma_iso_ctx(d); return NULL; } - memset(d->it_prg, 0, d->num_desc*sizeof(struct it_dma_prg *)); d->packet_size = packet_size; @@ -337,51 +309,28 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, } } - d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), - GFP_KERNEL); - d->buffer_prg_assignment = kmalloc(d->num_desc * sizeof(unsigned int), - GFP_KERNEL); - d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval), - GFP_KERNEL); - d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int), - GFP_KERNEL); - d->next_buffer = kmalloc(d->num_desc * sizeof(int), - GFP_KERNEL); - - if (d->buffer_status == NULL) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_status"); + d->buffer_status = + kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL); + d->buffer_prg_assignment = + kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL); + d->buffer_time = + kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL); + d->last_used_cmd = + kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL); + d->next_buffer = + kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL); + + if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time || + !d->last_used_cmd || !d->next_buffer) { + PRINT(KERN_ERR, ohci->host->id, + "Failed to allocate dma_iso_ctx member"); free_dma_iso_ctx(d); return NULL; } - if (d->buffer_prg_assignment == NULL) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_prg_assignment"); - free_dma_iso_ctx(d); - return NULL; - } - if (d->buffer_time == NULL) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_time"); - free_dma_iso_ctx(d); - return NULL; - } - if (d->last_used_cmd == NULL) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate last_used_cmd"); - free_dma_iso_ctx(d); - return NULL; - } - if (d->next_buffer == NULL) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate next_buffer"); - free_dma_iso_ctx(d); - return NULL; - } - memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); - memset(d->buffer_prg_assignment, 0, d->num_desc * sizeof(unsigned int)); - memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval)); - memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int)); - memset(d->next_buffer, -1, d->num_desc * sizeof(int)); spin_lock_init(&d->lock); - PRINT(KERN_INFO, ohci->host->id, "Iso %s DMA: %d buffers " + DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd); @@ -539,7 +488,10 @@ static void wakeup_dma_ir_ctx(unsigned long l) if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; - do_gettimeofday(&d->buffer_time[i]); + do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]); + dma_region_sync_for_cpu(&d->dma, + d->buffer_prg_assignment[i] * d->buf_size, + d->buf_size); } } @@ -765,8 +717,8 @@ static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d, return ret; } -static int __video1394_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static long video1394_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { struct file_ctx *ctx = (struct file_ctx *)file->private_data; struct ti_ohci *ohci = ctx->ohci; @@ -793,7 +745,7 @@ static int __video1394_ioctl(struct file *file, if (i == ISO_CHANNELS) { PRINT(KERN_ERR, ohci->host->id, "No free channel found"); - return EAGAIN; + return -EAGAIN; } if (!(ohci->ISO_channel_usage & mask)) { v.channel = i; @@ -809,7 +761,7 @@ static int __video1394_ioctl(struct file *file, } else { mask = (u64)0x1<host->id, "mask: %08X%08X usage: %08X%08X\n", + DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n", (u32)(mask>>32),(u32)(mask&0xffffffff), (u32)(ohci->ISO_channel_usage>>32), (u32)(ohci->ISO_channel_usage&0xffffffff)); @@ -855,7 +807,7 @@ static int __video1394_ioctl(struct file *file, v.buf_size = d->buf_size; list_add_tail(&d->link, &ctx->context_list); - PRINT(KERN_INFO, ohci->host->id, + DBGMSG(ohci->host->id, "iso context %d listen on channel %d", d->ctx, v.channel); } @@ -878,12 +830,12 @@ static int __video1394_ioctl(struct file *file, list_add_tail(&d->link, &ctx->context_list); - PRINT(KERN_INFO, ohci->host->id, + DBGMSG(ohci->host->id, "Iso context %d talk on channel %d", d->ctx, v.channel); } - if (copy_to_user((void *)arg, &v, sizeof(v))) { + if (copy_to_user(argp, &v, sizeof(v))) { /* FIXME : free allocated dma resources */ return -EFAULT; } @@ -923,7 +875,7 @@ static int __video1394_ioctl(struct file *file, d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel); if (d == NULL) return -ESRCH; - PRINT(KERN_INFO, ohci->host->id, "Iso context %d " + DBGMSG(ohci->host->id, "Iso context %d " "stop talking on channel %d", d->ctx, channel); free_dma_iso_ctx(d); @@ -935,13 +887,14 @@ static int __video1394_ioctl(struct file *file, struct dma_iso_ctx *d; int next_prg; - if (copy_from_user(&v, argp, sizeof(v))) + if (unlikely(copy_from_user(&v, argp, sizeof(v)))) return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); - if (d == NULL) return -EFAULT; + if (unlikely(d == NULL)) + return -EFAULT; - if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { + if (unlikely((v.buffer<0) || (v.buffer>=d->num_desc - 1))) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -949,7 +902,7 @@ static int __video1394_ioctl(struct file *file, spin_lock_irqsave(&d->lock,flags); - if (d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED) { + if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); @@ -985,7 +938,7 @@ static int __video1394_ioctl(struct file *file, else { /* Wake up dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { - PRINT(KERN_INFO, ohci->host->id, + DBGMSG(ohci->host->id, "Waking up iso dma ctx=%d", d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); } @@ -1000,13 +953,14 @@ static int __video1394_ioctl(struct file *file, struct dma_iso_ctx *d; int i = 0; - if (copy_from_user(&v, argp, sizeof(v))) + if (unlikely(copy_from_user(&v, argp, sizeof(v)))) return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); - if (d == NULL) return -EFAULT; + if (unlikely(d == NULL)) + return -EFAULT; - if ((v.buffer<0) || (v.buffer>d->num_desc - 1)) { + if (unlikely((v.buffer<0) || (v.buffer>d->num_desc - 1))) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -1046,7 +1000,6 @@ static int __video1394_ioctl(struct file *file, /* set time of buffer */ v.filltime = d->buffer_time[v.buffer]; -// printk("Buffer %d time %d\n", v.buffer, (d->buffer_time[v.buffer]).tv_usec); /* * Look ahead to see how many more buffers have been received @@ -1060,7 +1013,7 @@ static int __video1394_ioctl(struct file *file, spin_unlock_irqrestore(&d->lock, flags); v.buffer=i; - if (copy_to_user(argp, &v, sizeof(v))) + if (unlikely(copy_to_user(argp, &v, sizeof(v)))) return -EFAULT; return 0; @@ -1085,7 +1038,7 @@ static int __video1394_ioctl(struct file *file, } if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { - int buf_size = d->nb_cmd * sizeof(unsigned int); + int buf_size = d->nb_cmd * sizeof(*psizes); struct video1394_queue_variable __user *p = argp; unsigned int __user *qv; @@ -1104,7 +1057,7 @@ static int __video1394_ioctl(struct file *file, spin_lock_irqsave(&d->lock,flags); - // last_buffer is last_prg + /* last_buffer is last_prg */ next_prg = (d->last_buffer + 1) % d->num_desc; if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->host->id, @@ -1146,6 +1099,8 @@ static int __video1394_ioctl(struct file *file, DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); + dma_region_sync_for_device(&d->dma, + v.buffer * d->buf_size, d->buf_size); /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, @@ -1157,10 +1112,13 @@ static int __video1394_ioctl(struct file *file, else { /* Wake up dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { - PRINT(KERN_INFO, ohci->host->id, + DBGMSG(ohci->host->id, "Waking up iso transmit dma ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); + dma_region_sync_for_device(&d->dma, + v.buffer * d->buf_size, d->buf_size); + reg_write(ohci, d->ctrlSet, 0x1000); } } @@ -1208,15 +1166,6 @@ static int __video1394_ioctl(struct file *file, } } -static long video1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int err; - lock_kernel(); - err = __video1394_ioctl(file, cmd, arg); - unlock_kernel(); - return err; -} - /* * This maps the vmalloced and reserved buffer to user space. * @@ -1229,16 +1178,44 @@ static long video1394_ioctl(struct file *file, unsigned int cmd, unsigned long a static int video1394_mmap(struct file *file, struct vm_area_struct *vma) { struct file_ctx *ctx = (struct file_ctx *)file->private_data; - int res = -EINVAL; - lock_kernel(); if (ctx->current_ctx == NULL) { - PRINT(KERN_ERR, ctx->ohci->host->id, "Current iso context not set"); - } else - res = dma_region_mmap(&ctx->current_ctx->dma, file, vma); - unlock_kernel(); + PRINT(KERN_ERR, ctx->ohci->host->id, + "Current iso context not set"); + return -EINVAL; + } - return res; + return dma_region_mmap(&ctx->current_ctx->dma, file, vma); +} + +static unsigned int video1394_poll(struct file *file, poll_table *pt) +{ + struct file_ctx *ctx; + unsigned int mask = 0; + unsigned long flags; + struct dma_iso_ctx *d; + int i; + + ctx = file->private_data; + d = ctx->current_ctx; + if (d == NULL) { + PRINT(KERN_ERR, ctx->ohci->host->id, + "Current iso context not set"); + return POLLERR; + } + + poll_wait(file, &d->waitq, pt); + + spin_lock_irqsave(&d->lock, flags); + for (i = 0; i < d->num_desc; i++) { + if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) { + mask |= POLLIN | POLLRDNORM; + break; + } + } + spin_unlock_irqrestore(&d->lock, flags); + + return mask; } static int video1394_open(struct inode *inode, struct file *file) @@ -1251,13 +1228,12 @@ static int video1394_open(struct inode *inode, struct file *file) if (ohci == NULL) return -EIO; - ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL); - if (ctx == NULL) { + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx"); return -ENOMEM; } - memset(ctx, 0, sizeof(struct file_ctx)); ctx->ohci = ohci; INIT_LIST_HEAD(&ctx->context_list); ctx->current_ctx = NULL; @@ -1273,7 +1249,6 @@ static int video1394_release(struct inode *inode, struct file *file) struct list_head *lh, *next; u64 mask; - lock_kernel(); list_for_each_safe(lh, next, &ctx->context_list) { struct dma_iso_ctx *d; d = list_entry(lh, struct dma_iso_ctx, link); @@ -1284,7 +1259,7 @@ static int video1394_release(struct inode *inode, struct file *file) "is not being used", d->channel); else ohci->ISO_channel_usage &= ~mask; - PRINT(KERN_INFO, ohci->host->id, "On release: Iso %s context " + DBGMSG(ohci->host->id, "On release: Iso %s context " "%d stop listening on channel %d", d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit", d->ctx, d->channel); @@ -1294,7 +1269,6 @@ static int video1394_release(struct inode *inode, struct file *file) kfree(ctx); file->private_data = NULL; - unlock_kernel(); return 0; } @@ -1310,6 +1284,7 @@ static struct file_operations video1394_fops= #ifdef CONFIG_COMPAT .compat_ioctl = video1394_compat_ioctl, #endif + .poll = video1394_poll, .mmap = video1394_mmap, .open = video1394_open, .release = video1394_release @@ -1341,12 +1316,8 @@ static struct ieee1394_device_id video1394_id_table[] = { MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); static struct hpsb_protocol_driver video1394_driver = { - .name = "1394 Digital Camera Driver", + .name = VIDEO1394_DRIVER_NAME, .id_table = video1394_id_table, - .driver = { - .name = VIDEO1394_DRIVER_NAME, - .bus = &ieee1394_bus_type, - }, }; @@ -1370,12 +1341,9 @@ static void video1394_add_host (struct hpsb_host *host) hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; - class_simple_device_add(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, minor), NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id); - devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), - S_IFCHR | S_IRUSR | S_IWUSR, - "%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id); } @@ -1383,12 +1351,9 @@ static void video1394_remove_host (struct hpsb_host *host) { struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host); - if (ohci) { - class_simple_device_remove(MKDEV(IEEE1394_MAJOR, + if (ohci) + class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id)); - devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id); - } - return; } @@ -1529,12 +1494,8 @@ static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long a static void __exit video1394_exit_module (void) { hpsb_unregister_protocol(&video1394_driver); - hpsb_unregister_highlevel(&video1394_highlevel); - - devfs_remove(VIDEO1394_DRIVER_NAME); cdev_del(&video1394_cdev); - PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module"); } @@ -1551,15 +1512,12 @@ static int __init video1394_init_module (void) return ret; } - devfs_mk_dir(VIDEO1394_DRIVER_NAME); - hpsb_register_highlevel(&video1394_highlevel); ret = hpsb_register_protocol(&video1394_driver); if (ret) { PRINT_G(KERN_ERR, "video1394: failed to register protocol"); hpsb_unregister_highlevel(&video1394_highlevel); - devfs_remove(VIDEO1394_DRIVER_NAME); cdev_del(&video1394_cdev); return ret; } @@ -1571,4 +1529,3 @@ static int __init video1394_init_module (void) module_init(video1394_init_module); module_exit(video1394_exit_module); -MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16);