diff options
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r-- | drivers/staging/comedi/comedi_buf.c | 150 | ||||
-rw-r--r-- | drivers/staging/comedi/comedi_fops.c | 39 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/amplc_dio200_common.c | 16 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/amplc_pci230.c | 3 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/dt282x.c | 3 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/mite.c | 27 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/usbdux.c | 2 |
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; |