diff options
Diffstat (limited to 'arch/cris/arch-v32/drivers/sync_serial.c')
| -rw-r--r-- | arch/cris/arch-v32/drivers/sync_serial.c | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 47c377df6fb..bbb806b6883 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -13,12 +13,13 @@ #include <linux/errno.h> #include <linux/major.h> #include <linux/sched.h> -#include <linux/slab.h> +#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/timer.h> #include <linux/spinlock.h> +#include <linux/wait.h> #include <asm/io.h> #include <dma.h> @@ -33,7 +34,7 @@ #include <asm/sync_serial.h> -/* The receiver is a bit tricky beacuse of the continuous stream of data.*/ +/* The receiver is a bit tricky because of the continuous stream of data.*/ /* */ /* Three DMA descriptors are linked together. Each DMA descriptor is */ /* responsible for port->bufchunk of a common buffer. */ @@ -145,6 +146,7 @@ typedef struct sync_port spinlock_t lock; } sync_port; +static DEFINE_MUTEX(sync_serial_mutex); static int etrax_sync_serial_init(void); static void initialize_port(int portnbr); static inline int sync_data_avail(struct sync_port *port); @@ -153,7 +155,7 @@ static int sync_serial_open(struct inode *, struct file*); static int sync_serial_release(struct inode*, struct file*); static unsigned int sync_serial_poll(struct file *filp, poll_table *wait); -static int sync_serial_ioctl(struct inode*, struct file*, +static int sync_serial_ioctl(struct file *, unsigned int cmd, unsigned long arg); static ssize_t sync_serial_write(struct file * file, const char * buf, size_t count, loff_t *ppos); @@ -241,13 +243,14 @@ static struct sync_port ports[]= #define NBR_PORTS ARRAY_SIZE(ports) static const struct file_operations sync_serial_fops = { - .owner = THIS_MODULE, - .write = sync_serial_write, - .read = sync_serial_read, - .poll = sync_serial_poll, - .ioctl = sync_serial_ioctl, - .open = sync_serial_open, - .release = sync_serial_release + .owner = THIS_MODULE, + .write = sync_serial_write, + .read = sync_serial_read, + .poll = sync_serial_poll, + .unlocked_ioctl = sync_serial_ioctl, + .open = sync_serial_open, + .release = sync_serial_release, + .llseek = noop_llseek, }; static int __init etrax_sync_serial_init(void) @@ -429,23 +432,26 @@ static inline int sync_data_avail_to_end(struct sync_port *port) static int sync_serial_open(struct inode *inode, struct file *file) { int dev = iminor(inode); + int ret = -EBUSY; sync_port *port; reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; + mutex_lock(&sync_serial_mutex); DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev)); if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev)); - return -ENODEV; + ret = -ENODEV; + goto out; } port = &ports[dev]; /* Allow open this device twice (assuming one reader and one writer) */ if (port->busy == 2) { DEBUG(printk(KERN_DEBUG "Device is busy.. \n")); - return -EBUSY; + goto out; } @@ -459,7 +465,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) "synchronous serial 0 dma tr", &ports[0])) { printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); - return -EBUSY; + goto out; } else if (request_irq(DMA_IN_INTR_VECT, rx_interrupt, 0, @@ -467,7 +473,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) &ports[0])) { free_irq(DMA_OUT_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); - return -EBUSY; + goto out; } else if (crisv32_request_dma(OUT_DMA_NBR, "synchronous serial 0 dma tr", DMA_VERBOSE_ON_ERROR, @@ -476,7 +482,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) free_irq(DMA_OUT_INTR_VECT, &port[0]); free_irq(DMA_IN_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); - return -EBUSY; + goto out; } else if (crisv32_request_dma(IN_DMA_NBR, "synchronous serial 0 dma rec", DMA_VERBOSE_ON_ERROR, @@ -486,7 +492,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) free_irq(DMA_OUT_INTR_VECT, &port[0]); free_irq(DMA_IN_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); - return -EBUSY; + goto out; } #endif } @@ -499,7 +505,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) "synchronous serial 1 dma tr", &ports[1])) { printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ"); - return -EBUSY; + goto out; } else if (request_irq(DMA7_INTR_VECT, rx_interrupt, 0, @@ -507,7 +513,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) &ports[1])) { free_irq(DMA6_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); - return -EBUSY; + goto out; } else if (crisv32_request_dma( SYNC_SER1_TX_DMA_NBR, "synchronous serial 1 dma tr", @@ -517,7 +523,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(DMA7_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); - return -EBUSY; + goto out; } else if (crisv32_request_dma( SYNC_SER1_RX_DMA_NBR, "synchronous serial 3 dma rec", @@ -528,7 +534,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(DMA7_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel"); - return -EBUSY; + goto out; } #endif } @@ -554,7 +560,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) "synchronous serial manual irq", &ports[0])) { printk("Can't allocate sync serial manual irq"); - return -EBUSY; + goto out; } } #ifdef CONFIG_ETRAXFS @@ -565,7 +571,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) "synchronous serial manual irq", &ports[1])) { printk(KERN_CRIT "Can't allocate sync serial manual irq"); - return -EBUSY; + goto out; } } #endif @@ -578,7 +584,10 @@ static int sync_serial_open(struct inode *inode, struct file *file) } /* port->init_irqs */ port->busy++; - return 0; + ret = 0; +out: + mutex_unlock(&sync_serial_mutex); + return ret; } static int sync_serial_release(struct inode *inode, struct file *file) @@ -601,7 +610,7 @@ static int sync_serial_release(struct inode *inode, struct file *file) static unsigned int sync_serial_poll(struct file *file, poll_table *wait) { - int dev = iminor(file->f_path.dentry->d_inode); + int dev = iminor(file_inode(file)); unsigned int mask = 0; sync_port *port; DEBUGPOLL( static unsigned int prev_mask = 0; ); @@ -644,12 +653,12 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) return mask; } -static int sync_serial_ioctl(struct inode *inode, struct file *file, +static int sync_serial_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int return_val = 0; int dma_w_size = regk_dma_set_w_size1; - int dev = iminor(file->f_path.dentry->d_inode); + int dev = iminor(file_inode(file)); sync_port *port; reg_sser_rw_tr_cfg tr_cfg; reg_sser_rw_rec_cfg rec_cfg; @@ -955,11 +964,23 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, return return_val; } +static long sync_serial_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + mutex_lock(&sync_serial_mutex); + ret = sync_serial_ioctl_unlocked(file, cmd, arg); + mutex_unlock(&sync_serial_mutex); + + return ret; +} + /* NOTE: sync_serial_write does not support concurrency */ static ssize_t sync_serial_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev = iminor(file->f_path.dentry->d_inode); + int dev = iminor(file_inode(file)); DECLARE_WAITQUEUE(wait, current); struct sync_port *port; int trunc_count; @@ -1082,7 +1103,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, static ssize_t sync_serial_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - int dev = iminor(file->f_path.dentry->d_inode); + int dev = iminor(file_inode(file)); int avail; sync_port *port; unsigned char* start; @@ -1124,7 +1145,8 @@ static ssize_t sync_serial_read(struct file * file, char * buf, if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); if (signal_pending(current)) return -EINTR; |
