- fix all XXX showstoppers
- disable IR/IT DMA interrupts on shutdown
- flush pci writes to the card by issuing a read
- - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+ - character device dispatching
- switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
- keep all video_cards in a list (for open() via chardev), set file->private_data = video
- dv1394_poll should indicate POLLIN when receiving buffers are available
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
-#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
+#include "dv1394.h"
+#include "dv1394-private.h"
+#include "highlevel.h"
+#include "hosts.h"
#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "ieee1394_hotplug.h"
#include "ieee1394_types.h"
#include "nodemgr.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "dv1394.h"
-#include "dv1394-private.h"
-
#include "ohci1394.h"
-#ifndef virt_to_page
-#define virt_to_page(x) MAP_NR(x)
-#endif
-
-#ifndef vmalloc_32
-#define vmalloc_32(x) vmalloc(x)
-#endif
-
-
/* DEBUG LEVELS:
0 - no debugging messages
1 - some debugging messages, but none during DMA frame transmission
#if DV1394_DEBUG_LEVEL >= 2
#define irq_printk( args... ) printk( args )
#else
-#define irq_printk( args... )
+#define irq_printk( args... ) do {} while (0)
#endif
#if DV1394_DEBUG_LEVEL >= 1
#define debug_printk( args... ) printk( args)
#else
-#define debug_printk( args... )
+#define debug_printk( args... ) do {} while (0)
#endif
/* issue a dummy PCI read to force the preceding write
static void it_tasklet_func(unsigned long data);
static void ir_tasklet_func(unsigned long data);
+#ifdef CONFIG_COMPAT
+static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+#endif
+
/* GLOBAL DATA */
/* list of all video_cards */
static LIST_HEAD(dv1394_cards);
-static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dv1394_cards_lock);
/* translate from a struct file* to the corresponding struct video_card* */
Frame_prepare() must be called OUTSIDE the video->spinlock.
However, frame_prepare() must still be serialized, so
- it should be called WITH the video->sem taken.
+ it should be called WITH the video->mtx taken.
*/
static void frame_prepare(struct video_card *video, unsigned int this_frame)
init.api_version = DV1394_API_VERSION;
init.n_frames = DV1394_MAX_FRAMES / 4;
- /* the following are now set via devfs */
init.channel = video->channel;
init.format = video->pal_or_ntsc;
init.cip_n = video->cip_n;
error-prone code in dv1394.
*/
-int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
+static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_card *video = file_to_video_card(file);
int retval = -EINVAL;
/* serialize mmap */
- down(&video->sem);
+ mutex_lock(&video->mtx);
if ( ! video_card_initialized(video) ) {
retval = do_dv1394_init_default(video);
retval = dma_region_mmap(&video->dv_buf, file, vma);
out:
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return retval;
}
static int dv1394_fasync(int fd, struct file *file, int on)
{
/* I just copied this code verbatim from Alan Cox's mouse driver example
- (linux/Documentation/DocBook/) */
+ (Documentation/DocBook/) */
struct video_card *video = file_to_video_card(file);
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem))
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
} else {
- if (down_interruptible(&video->sem))
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
}
if ( !video_card_initialized(video) ) {
ret = do_dv1394_init_default(video);
if (ret) {
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
}
remove_wait_queue(&video->waitq, &wait);
set_current_state(TASK_RUNNING);
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem))
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
} else {
- if (down_interruptible(&video->sem))
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
}
if ( !video_card_initialized(video) ) {
ret = do_dv1394_init_default(video);
if (ret) {
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
video->continuity_counter = -1;
remove_wait_queue(&video->waitq, &wait);
set_current_state(TASK_RUNNING);
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
/*** DEVICE IOCTL INTERFACE ************************************************/
-/* I *think* the VFS serializes ioctl() for us, so we don't have to worry
- about situations like having two threads in here at once... */
-
-static int dv1394_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct video_card *video = file_to_video_card(file);
unsigned long flags;
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem))
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
} else {
- if (down_interruptible(&video->sem))
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
}
}
out:
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
-
-
/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
static int dv1394_open(struct inode *inode, struct file *file)
{
struct video_card *video = NULL;
- /* if the device was opened through devfs, then file->private_data
- has already been set to video by devfs */
if (file->private_data) {
video = (struct video_card*) file->private_data;
{
.owner = THIS_MODULE,
.poll = dv1394_poll,
- .ioctl = dv1394_ioctl,
+ .unlocked_ioctl = dv1394_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = dv1394_compat_ioctl,
+#endif
.mmap = dv1394_mmap,
.open = dv1394_open,
.write = dv1394_write,
MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
static struct hpsb_protocol_driver dv1394_driver = {
- .name = "DV/1394 Driver",
+ .name = "dv1394",
.id_table = dv1394_id_table,
- .driver = {
- .name = "dv1394",
- .bus = &ieee1394_bus_type,
- },
};
unsigned long flags;
int i;
- video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+ video = kzalloc(sizeof(*video), GFP_KERNEL);
if (!video) {
printk(KERN_ERR "dv1394: cannot allocate video_card\n");
- goto err;
+ return -1;
}
- memset(video, 0, sizeof(struct video_card));
-
video->ohci = ohci;
/* lower 2 bits of id indicate which of four "plugs"
per host */
clear_bit(0, &video->open);
spin_lock_init(&video->spinlock);
video->dma_running = 0;
- init_MUTEX(&video->sem);
+ mutex_init(&video->mtx);
init_waitqueue_head(&video->waitq);
video->fasync = NULL;
list_add_tail(&video->list, &dv1394_cards);
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
- if (devfs_mk_cdev(MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394*16 + video->id),
- S_IFCHR|S_IRUGO|S_IWUGO,
- "ieee1394/dv/host%d/%s/%s",
- (video->id>>2),
- (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
- (video->mode == MODE_RECEIVE ? "in" : "out")) < 0)
- goto err_free;
-
debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
-
return 0;
-
- err_free:
- kfree(video);
- err:
- return -1;
}
static void dv1394_un_init(struct video_card *video)
{
- char buf[32];
-
/* obviously nobody has the driver open at this point */
do_dv1394_shutdown(video, 1);
- snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
- (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
- (video->mode == MODE_RECEIVE ? "in" : "out")
- );
-
- devfs_remove("ieee1394/%s", buf);
kfree(video);
}
{
struct video_card *video;
unsigned long flags;
- int id = host->id;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
+ int id = host->id, found_ohci_card = 0;
/* find the corresponding video_cards */
do {
if ((tmp_vid->id >> 2) == id) {
list_del(&tmp_vid->list);
video = tmp_vid;
+ found_ohci_card = 1;
break;
}
}
dv1394_un_init(video);
} while (video != NULL);
- devfs_remove("ieee1394/dv/host%d/NTSC", id);
- devfs_remove("ieee1394/dv/host%d/PAL", id);
- devfs_remove("ieee1394/dv/host%d", id);
+ if (found_ohci_card)
+ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id << 2)));
}
static void dv1394_add_host (struct hpsb_host *host)
ohci = (struct ti_ohci *)host->hostdata;
- devfs_mk_dir("ieee1394/dv/host%d", id);
- devfs_mk_dir("ieee1394/dv/host%d/NTSC", id);
- devfs_mk_dir("ieee1394/dv/host%d/PAL", id);
+ class_device_create(hpsb_protocol_class, NULL, MKDEV(
+ IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
+ NULL, "dv1394-%d", id);
dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
u32 dropped_frames;
};
-static int handle_dv1394_init(unsigned int fd, unsigned int cmd, unsigned long arg,
- struct file *file)
+/* RED-PEN: this should use compat_alloc_userspace instead */
+
+static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg)
{
struct dv1394_init32 dv32;
struct dv1394_init dv;
mm_segment_t old_fs;
int ret;
- if (file->f_op->ioctl != dv1394_ioctl)
+ if (file->f_op->unlocked_ioctl != dv1394_ioctl)
return -EFAULT;
- if (copy_from_user(&dv32, (void *)arg, sizeof(dv32)))
+ if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
return -EFAULT;
dv.api_version = dv32.api_version;
old_fs = get_fs();
set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file->f_dentry->d_inode, file,
- DV1394_IOC_INIT, (unsigned long)&dv);
+ ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
set_fs(old_fs);
return ret;
}
-static int handle_dv1394_get_status(unsigned int fd, unsigned int cmd, unsigned long arg,
- struct file *file)
+static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg)
{
struct dv1394_status32 dv32;
struct dv1394_status dv;
mm_segment_t old_fs;
int ret;
- if (file->f_op->ioctl != dv1394_ioctl)
+ if (file->f_op->unlocked_ioctl != dv1394_ioctl)
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file->f_dentry->d_inode, file,
- DV1394_IOC_GET_STATUS, (unsigned long)&dv);
+ ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
set_fs(old_fs);
if (!ret) {
dv32.n_clear_frames = dv.n_clear_frames;
dv32.dropped_frames = dv.dropped_frames;
- if (copy_to_user((struct dv1394_status32 *)arg, &dv32, sizeof(dv32)))
+ if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32)))
ret = -EFAULT;
}
return ret;
}
+
+
+
+static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case DV1394_IOC_SHUTDOWN:
+ case DV1394_IOC_SUBMIT_FRAMES:
+ case DV1394_IOC_WAIT_FRAMES:
+ case DV1394_IOC_RECEIVE_FRAMES:
+ case DV1394_IOC_START_RECEIVE:
+ return dv1394_ioctl(file, cmd, arg);
+
+ case DV1394_IOC32_INIT:
+ return handle_dv1394_init(file, cmd, arg);
+ case DV1394_IOC32_GET_STATUS:
+ return handle_dv1394_get_status(file, cmd, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
#endif /* CONFIG_COMPAT */
static void __exit dv1394_exit_module(void)
{
-#ifdef CONFIG_COMPAT
- int ret;
-
- ret = unregister_ioctl32_conversion(DV1394_IOC_SHUTDOWN);
- ret |= unregister_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES);
- ret |= unregister_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES);
- ret |= unregister_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES);
- ret |= unregister_ioctl32_conversion(DV1394_IOC_START_RECEIVE);
- ret |= unregister_ioctl32_conversion(DV1394_IOC32_INIT);
- ret |= unregister_ioctl32_conversion(DV1394_IOC32_GET_STATUS);
- if (ret)
- printk(KERN_ERR "dv1394: Error unregistering ioctl32 translations\n");
-#endif
-
hpsb_unregister_protocol(&dv1394_driver);
-
hpsb_unregister_highlevel(&dv1394_highlevel);
cdev_del(&dv1394_cdev);
- devfs_remove("ieee1394/dv");
}
static int __init dv1394_init_module(void)
{
int ret;
+ printk(KERN_WARNING
+ "WARNING: The dv1394 driver is unsupported and will be removed "
+ "from Linux soon. Use raw1394 instead.\n");
+
cdev_init(&dv1394_cdev, &dv1394_fops);
dv1394_cdev.owner = THIS_MODULE;
kobject_set_name(&dv1394_cdev.kobj, "dv1394");
return ret;
}
- devfs_mk_dir("ieee1394/dv");
-
hpsb_register_highlevel(&dv1394_highlevel);
ret = hpsb_register_protocol(&dv1394_driver);
if (ret) {
printk(KERN_ERR "dv1394: failed to register protocol\n");
hpsb_unregister_highlevel(&dv1394_highlevel);
- devfs_remove("ieee1394/dv");
cdev_del(&dv1394_cdev);
return ret;
}
-#ifdef CONFIG_COMPAT
- {
- /* First compatible ones */
- ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL);
- ret |= register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL);
- ret |= register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL);
- ret |= register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL);
- ret |= register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL);
-
- /* These need to be handled by translation */
- ret |= register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init);
- ret |= register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status);
- if (ret)
- printk(KERN_ERR "dv1394: Error registering ioctl32 translations\n");
- }
-#endif
-
return 0;
}
module_init(dv1394_init_module);
module_exit(dv1394_exit_module);
-MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16);