},
};
+struct pcl818_dma_desc {
+ void *virt_addr; /* virtual address of DMA buffer */
+ dma_addr_t hw_addr; /* hardware (bus) address of DMA buffer */
+ unsigned int size; /* transfer size (in bytes) */
+};
+
struct pcl818_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
- unsigned int dmapages;
unsigned int hwdmasize;
- unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- int next_dma_buf; /* which DMA buffer will be used next round */
+ struct pcl818_dma_desc dma_desc[2];
+ int cur_dma;
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
- int ai_act_scan; /* how many scans we finished */
- int ai_act_chan; /* actual position in actual scan */
unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
unsigned int act_chanlist_len; /* how long is actual MUX list */
unsigned int act_chanlist_pos; /* actual position in MUX list */
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
+ struct pcl818_dma_desc *dma = &devpriv->dma_desc[0];
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int flags;
- unsigned int bytes;
disable_dma(devpriv->dma); /* disable dma */
- bytes = devpriv->hwdmasize;
if (cmd->stop_src == TRIG_COUNT) {
- bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
- devpriv->last_dma_run = bytes % devpriv->hwdmasize;
+ dma->size = cmd->stop_arg * comedi_bytes_per_scan(s);
+ devpriv->dma_runs_to_end = dma->size / devpriv->hwdmasize;
+ devpriv->last_dma_run = dma->size % devpriv->hwdmasize;
devpriv->dma_runs_to_end--;
if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize;
+ dma->size = devpriv->hwdmasize;
+ } else {
+ dma->size = devpriv->hwdmasize;
}
- devpriv->next_dma_buf = 0;
+ devpriv->cur_dma = 0;
set_dma_mode(devpriv->dma, DMA_MODE_READ);
flags = claim_dma_lock();
clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
+ set_dma_addr(devpriv->dma, dma->hw_addr);
+ set_dma_count(devpriv->dma, dma->size);
release_dma_lock(flags);
enable_dma(devpriv->dma);
}
{
struct pcl818_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ struct pcl818_dma_desc *dma;
unsigned long flags;
disable_dma(devpriv->dma);
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ devpriv->cur_dma = 1 - devpriv->cur_dma;
if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
/* switch dma bufs */
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ dma = &devpriv->dma_desc[devpriv->cur_dma];
if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
- set_dma_count(devpriv->dma, devpriv->hwdmasize);
+ dma->size = devpriv->hwdmasize;
else
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ dma->size = devpriv->last_dma_run;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma, dma->hw_addr);
+ set_dma_count(devpriv->dma, dma->size);
release_dma_lock(flags);
enable_dma(devpriv->dma);
}
struct pcl818_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- s->async->events |= COMEDI_CB_BLOCK;
-
devpriv->act_chanlist_pos++;
if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
devpriv->act_chanlist_pos = 0;
- s->async->cur_chan++;
- if (s->async->cur_chan >= cmd->chanlist_len) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- s->async->events |= COMEDI_CB_EOS;
- }
-
- if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) {
- /* all data sampled */
+ if (cmd->stop_src == TRIG_COUNT &&
+ s->async->scans_done >= cmd->stop_arg) {
s->async->events |= COMEDI_CB_EOA;
return false;
}
if (pcl818_ai_dropout(dev, s, chan))
return;
- comedi_buf_put(s, val);
+ comedi_buf_write_samples(s, &val, 1);
pcl818_ai_next_chan(dev, s);
}
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
- unsigned short *ptr;
+ struct pcl818_dma_desc *dma = &devpriv->dma_desc[devpriv->cur_dma];
+ unsigned short *ptr = dma->virt_addr;
+ unsigned int nsamples = comedi_bytes_to_samples(s, dma->size);
unsigned int chan;
unsigned int val;
- int i, len, bufptr;
+ int i;
pcl818_ai_setup_next_dma(dev, s);
- ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
-
- len = devpriv->hwdmasize >> 1;
- bufptr = 0;
-
- for (i = 0; i < len; i++) {
- val = ptr[bufptr++];
+ for (i = 0; i < nsamples; i++) {
+ val = ptr[i];
chan = val & 0xf;
val = (val >> 4) & s->maxdata;
if (pcl818_ai_dropout(dev, s, chan))
break;
- comedi_buf_put(s, val);
+ comedi_buf_write_samples(s, &val, 1);
if (!pcl818_ai_next_chan(dev, s))
break;
if (pcl818_ai_dropout(dev, s, chan))
break;
- comedi_buf_put(s, val);
+ comedi_buf_write_samples(s, &val, 1);
if (!pcl818_ai_next_chan(dev, s))
break;
struct comedi_device *dev = d;
struct pcl818_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
if (!dev->attached || !devpriv->ai_cmd_running) {
pcl818_ai_clear_eoc(dev);
* being reprogrammed while a DMA transfer is in
* progress.
*/
- devpriv->ai_act_scan = 0;
+ s->async->scans_done = cmd->stop_arg;
s->cancel(dev, s);
return IRQ_HANDLED;
}
pcl818_ai_clear_eoc(dev);
- cfc_handle_events(dev, s);
+ comedi_handle_events(dev, s);
return IRQ_HANDLED;
}
pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_act_scan = cmd->stop_arg;
- devpriv->ai_act_chan = 0;
devpriv->ai_cmd_running = 1;
devpriv->ai_cmd_canceled = 0;
devpriv->act_chanlist_pos = 0;
if (devpriv->dma) {
if (cmd->stop_src == TRIG_NONE ||
- (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) {
+ (cmd->stop_src == TRIG_COUNT &&
+ s->async->scans_done < cmd->stop_arg)) {
if (!devpriv->ai_cmd_canceled) {
/*
* Wait for running dma transfer to end,
}
}
+static int pcl818_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct pcl818_dma_desc *dma;
+ int i;
+
+ if (!(dma_chan == 3 || dma_chan == 1))
+ return 0;
+
+ if (request_dma(dma_chan, dev->board_name))
+ return 0;
+ devpriv->dma = dma_chan;
+
+ devpriv->hwdmasize = PAGE_SIZE * 4; /* we need 16KB */
+
+ for (i = 0; i < 2; i++) {
+ dma = &devpriv->dma_desc[i];
+
+ dma->virt_addr = dma_alloc_coherent(NULL, devpriv->hwdmasize,
+ &dma->hw_addr, GFP_KERNEL);
+ if (!dma->virt_addr)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void pcl818_free_dma(struct comedi_device *dev)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct pcl818_dma_desc *dma;
+ int i;
+
+ if (!devpriv)
+ return;
+
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ for (i = 0; i < 2; i++) {
+ dma = &devpriv->dma_desc[i];
+ if (dma->virt_addr)
+ dma_free_coherent(NULL, devpriv->hwdmasize,
+ dma->virt_addr, dma->hw_addr);
+ }
+}
+
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl818_board *board = dev->board_ptr;
struct pcl818_private *devpriv;
struct comedi_subdevice *s;
int ret;
- int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
devpriv->usefifo = 1;
/* we need an IRQ to do DMA on channel 3 or 1 */
- if (dev->irq && board->has_dma &&
- (it->options[2] == 3 || it->options[2] == 1)) {
- ret = request_dma(it->options[2], dev->board_name);
- if (ret) {
- dev_err(dev->class_dev,
- "unable to request DMA channel %d\n",
- it->options[2]);
- return -EBUSY;
- }
- devpriv->dma = it->options[2];
-
- devpriv->dmapages = 2; /* we need 16KB */
- devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
- for (i = 0; i < 2; i++) {
- unsigned long dmabuf;
-
- dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
- if (!dmabuf)
- return -ENOMEM;
-
- devpriv->dmabuf[i] = dmabuf;
- devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
- }
+ if (dev->irq && board->has_dma) {
+ ret = pcl818_alloc_dma(dev, it->options[2]);
+ if (ret)
+ return ret;
}
ret = comedi_alloc_subdevices(dev, 4);
s->range_table = &range_unknown;
}
s->insn_write = pcl818_ao_insn_write;
- s->insn_read = comedi_readback_insn_read;
ret = comedi_alloc_subdev_readback(s);
if (ret)
if (devpriv) {
pcl818_ai_cancel(dev, dev->read_subdev);
pcl818_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
+ pcl818_free_dma(dev);
comedi_legacy_detach(dev);
}