summaryrefslogtreecommitdiff
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/comedi_buf.c150
-rw-r--r--drivers/staging/comedi/comedi_fops.c39
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c16
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c3
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c3
-rw-r--r--drivers/staging/comedi/drivers/mite.c27
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c2
7 files changed, 142 insertions, 98 deletions
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index d2c8cc72a99d..3ef3ddabf139 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -27,18 +27,19 @@ static void comedi_buf_map_kref_release(struct kref *kref)
unsigned int i;
if (bm->page_list) {
- for (i = 0; i < bm->n_pages; i++) {
- buf = &bm->page_list[i];
- clear_bit(PG_reserved,
- &(virt_to_page(buf->virt_addr)->flags));
- if (bm->dma_dir != DMA_NONE) {
-#ifdef CONFIG_HAS_DMA
- dma_free_coherent(bm->dma_hw_dev,
- PAGE_SIZE,
- buf->virt_addr,
- buf->dma_addr);
-#endif
- } else {
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ dma_free_coherent(bm->dma_hw_dev,
+ PAGE_SIZE * bm->n_pages,
+ buf->virt_addr, buf->dma_addr);
+ } else {
+ for (i = 0; i < bm->n_pages; i++) {
+ buf = &bm->page_list[i];
+ ClearPageReserved(virt_to_page(buf->virt_addr));
free_page((unsigned long)buf->virt_addr);
}
}
@@ -57,7 +58,8 @@ static void __comedi_buf_free(struct comedi_device *dev,
unsigned long flags;
if (async->prealloc_buf) {
- vunmap(async->prealloc_buf);
+ if (s->async_dma_dir == DMA_NONE)
+ vunmap(async->prealloc_buf);
async->prealloc_buf = NULL;
async->prealloc_bufsz = 0;
}
@@ -69,6 +71,72 @@ static void __comedi_buf_free(struct comedi_device *dev,
comedi_buf_map_put(bm);
}
+static struct comedi_buf_map *
+comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
+ unsigned int n_pages)
+{
+ struct comedi_buf_map *bm;
+ struct comedi_buf_page *buf;
+ unsigned int i;
+
+ bm = kzalloc(sizeof(*bm), GFP_KERNEL);
+ if (!bm)
+ return NULL;
+
+ kref_init(&bm->refcount);
+ bm->dma_dir = dma_dir;
+ if (bm->dma_dir != DMA_NONE) {
+ /* Need ref to hardware device to free buffer later. */
+ bm->dma_hw_dev = get_device(dev->hw_dev);
+ }
+
+ bm->page_list = vzalloc(sizeof(*buf) * n_pages);
+ if (!bm->page_list)
+ goto err;
+
+ if (bm->dma_dir != DMA_NONE) {
+ void *virt_addr;
+ dma_addr_t dma_addr;
+
+ /*
+ * Currently, the DMA buffer needs to be allocated as a
+ * single block so that it can be mmap()'ed.
+ */
+ virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
+ PAGE_SIZE * n_pages, &dma_addr,
+ GFP_KERNEL);
+ if (!virt_addr)
+ goto err;
+
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ buf->virt_addr = virt_addr + (i << PAGE_SHIFT);
+ buf->dma_addr = dma_addr + (i << PAGE_SHIFT);
+ }
+
+ bm->n_pages = i;
+ } else {
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!buf->virt_addr)
+ break;
+
+ SetPageReserved(virt_to_page(buf->virt_addr));
+ }
+
+ bm->n_pages = i;
+ if (i < n_pages)
+ goto err;
+ }
+
+ return bm;
+
+err:
+ comedi_buf_map_put(bm);
+ return NULL;
+}
+
static void __comedi_buf_alloc(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int n_pages)
@@ -86,57 +154,37 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
return;
}
- bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL);
+ bm = comedi_buf_map_alloc(dev, s->async_dma_dir, n_pages);
if (!bm)
return;
- kref_init(&bm->refcount);
spin_lock_irqsave(&s->spin_lock, flags);
async->buf_map = bm;
spin_unlock_irqrestore(&s->spin_lock, flags);
- bm->dma_dir = s->async_dma_dir;
- if (bm->dma_dir != DMA_NONE)
- /* Need ref to hardware device to free buffer later. */
- bm->dma_hw_dev = get_device(dev->hw_dev);
- bm->page_list = vzalloc(sizeof(*buf) * n_pages);
- if (bm->page_list)
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ async->prealloc_buf = buf->virt_addr;
+ } else {
pages = vmalloc(sizeof(struct page *) * n_pages);
+ if (!pages)
+ return;
- if (!pages)
- return;
-
- for (i = 0; i < n_pages; i++) {
- buf = &bm->page_list[i];
- if (bm->dma_dir != DMA_NONE)
-#ifdef CONFIG_HAS_DMA
- buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
- PAGE_SIZE,
- &buf->dma_addr,
- GFP_KERNEL |
- __GFP_COMP);
-#else
- break;
-#endif
- else
- buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
- if (!buf->virt_addr)
- break;
-
- set_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags));
-
- pages[i] = virt_to_page(buf->virt_addr);
- }
- spin_lock_irqsave(&s->spin_lock, flags);
- bm->n_pages = i;
- spin_unlock_irqrestore(&s->spin_lock, flags);
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ pages[i] = virt_to_page(buf->virt_addr);
+ }
- /* vmap the prealloc_buf if all the pages were allocated */
- if (i == n_pages)
+ /* vmap the pages to prealloc_buf */
async->prealloc_buf = vmap(pages, n_pages, VM_MAP,
COMEDI_PAGE_PROTECTION);
- vfree(pages);
+ vfree(pages);
+ }
}
void comedi_buf_map_get(struct comedi_buf_map *bm)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f6d1287c7b83..08d1bbbebf2d 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2301,11 +2301,12 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
struct comedi_subdevice *s;
struct comedi_async *async;
struct comedi_buf_map *bm = NULL;
+ struct comedi_buf_page *buf;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
- int retval;
+ int retval = 0;
/*
* 'trylock' avoids circular dependency with current->mm->mmap_sem
@@ -2361,24 +2362,36 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
retval = -EINVAL;
goto done;
}
- for (i = 0; i < n_pages; ++i) {
- struct comedi_buf_page *buf = &bm->page_list[i];
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr,
+ buf->dma_addr, n_pages * PAGE_SIZE);
+ } else {
+ for (i = 0; i < n_pages; ++i) {
+ unsigned long pfn;
+
+ buf = &bm->page_list[i];
+ pfn = page_to_pfn(virt_to_page(buf->virt_addr));
+ retval = remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+ PAGE_SHARED);
+ if (retval)
+ break;
- if (remap_pfn_range(vma, start,
- page_to_pfn(virt_to_page(buf->virt_addr)),
- PAGE_SIZE, PAGE_SHARED)) {
- retval = -EAGAIN;
- goto done;
+ start += PAGE_SIZE;
}
- start += PAGE_SIZE;
}
- vma->vm_ops = &comedi_vm_ops;
- vma->vm_private_data = bm;
+ if (retval == 0) {
+ vma->vm_ops = &comedi_vm_ops;
+ vma->vm_private_data = bm;
- vma->vm_ops->open(vma);
+ vma->vm_ops->open(vma);
+ }
- retval = 0;
done:
up_read(&dev->attach_lock);
comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 8697dc02ffb4..0b2f04b02ebc 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -46,18 +46,6 @@ static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
((source & 030) << 3) | (source & 007);
}
-static unsigned char clk_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
-static unsigned char gat_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
/*
* Periods of the internal clock sources in nanoseconds.
*/
@@ -489,7 +477,7 @@ static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
unsigned int offset = dio200_subdev_8254_offset(dev, s);
dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
- gat_sce((offset >> 2) & 1, chan, src));
+ clk_gat_sce((offset >> 2) & 1, chan, src));
}
static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
@@ -500,7 +488,7 @@ static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
unsigned int offset = dio200_subdev_8254_offset(dev, s);
dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
- clk_sce((offset >> 2) & 1, chan, src));
+ clk_gat_sce((offset >> 2) & 1, chan, src));
}
static int dio200_subdev_8254_config(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 65f60c2b702a..f7e673121864 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2330,7 +2330,8 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
devpriv->intr_running = false;
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
comedi_handle_events(dev, s_ai);
return IRQ_HANDLED;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 3be927f1d3a9..e15e33ed94ae 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -557,7 +557,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
}
#endif
comedi_handle_events(dev, s);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
return IRQ_RETVAL(handled);
}
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 639ec1586976..cc9fc263573e 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -558,7 +558,14 @@ void mite_prep_dma(struct mite_channel *mite_chan,
}
EXPORT_SYMBOL_GPL(mite_prep_dma);
-static struct mite_channel *__mite_request_channel(struct mite *mite,
+/**
+ * mite_request_channel_in_range() - Request a MITE dma channel.
+ * @mite: MITE device.
+ * @ring: MITE dma ring.
+ * @min_channel: minimum channel index to use.
+ * @max_channel: maximum channel index to use.
+ */
+struct mite_channel *mite_request_channel_in_range(struct mite *mite,
struct mite_ring *ring,
unsigned int min_channel,
unsigned int max_channel)
@@ -583,21 +590,6 @@ static struct mite_channel *__mite_request_channel(struct mite *mite,
spin_unlock_irqrestore(&mite->lock, flags);
return mite_chan;
}
-
-/**
- * mite_request_channel_in_range() - Request a MITE dma channel.
- * @mite: MITE device.
- * @ring: MITE dma ring.
- * @min_channel: minimum channel index to use.
- * @max_channel: maximum channel index to use.
- */
-struct mite_channel *mite_request_channel_in_range(struct mite *mite,
- struct mite_ring *ring,
- unsigned int min_channel,
- unsigned int max_channel)
-{
- return __mite_request_channel(mite, ring, min_channel, max_channel);
-}
EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
/**
@@ -608,7 +600,8 @@ EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
struct mite_channel *mite_request_channel(struct mite *mite,
struct mite_ring *ring)
{
- return __mite_request_channel(mite, ring, 0, mite->num_channels - 1);
+ return mite_request_channel_in_range(mite, ring, 0,
+ mite->num_channels - 1);
}
EXPORT_SYMBOL_GPL(mite_request_channel);
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index b8f54b7fb34a..0350f303d557 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -1226,7 +1226,7 @@ static int usbdux_pwm_period(struct comedi_device *dev,
unsigned int period)
{
struct usbdux_private *devpriv = dev->private;
- int fx2delay = 255;
+ int fx2delay;
if (period < MIN_PWM_PERIOD)
return -EAGAIN;