pcmuio.c revision 1699d80aef8ba7992d5f4176aed3504db8cffaf9
16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 29e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * pcmuio.c 39e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Comedi driver for Winsystems PC-104 based 48/96-channel DIO boards. 49e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 59e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * COMEDI - Linux Control and Measurement Device Interface 69e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> 79e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 89e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is free software; you can redistribute it and/or modify 99e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * it under the terms of the GNU General Public License as published by 109e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the Free Software Foundation; either version 2 of the License, or 119e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (at your option) any later version. 129e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 139e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is distributed in the hope that it will be useful, 149e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * but WITHOUT ANY WARRANTY; without even the implied warranty of 159e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 169e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * GNU General Public License for more details. 179e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */ 186baef150380d561a4d695a6be4fc509821c23611Calin Culianu 196baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 209e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Driver: pcmuio 219e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Description: Winsystems PC-104 based 48/96-channel DIO boards. 229e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Devices: (Winsystems) PCM-UIO48A [pcmuio48] 239e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (Winsystems) PCM-UIO96A [pcmuio96] 249e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Author: Calin Culianu <calin@ajvar.org> 259e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Updated: Fri, 13 Jan 2006 12:01:01 -0500 269e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Status: works 279e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 289e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * A driver for the relatively straightforward-to-program PCM-UIO48A and 299e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * PCM-UIO96A boards from Winsystems. These boards use either one or two 309e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). This 319e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chip is interesting in that each I/O line is individually programmable 329e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for INPUT or OUTPUT (thus comedi_dio_config can be done on a per-channel 339e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * basis). Also, each chip supports edge-triggered interrupts for the first 349e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 24 I/O lines. Of course, since the 96-channel version of the board has 359e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * two ASICs, it can detect polarity changes on up to 48 I/O lines. Since 369e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * this is essentially an (non-PnP) ISA board, I/O Address and IRQ selection 379e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * are done through jumpers on the board. You need to pass that information 389e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * to this driver as the first and second comedi_config option, respectively. 399e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that the 48-channel version uses 16 bytes of IO memory and the 96- 409e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * channel version uses 32-bytes (in case you are worried about conflicts). 419e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * The 48-channel board is split into two 24-channel comedi subdevices. The 429e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96-channel board is split into 4 24-channel DIO subdevices. 439e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 449e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that IRQ support has been added, but it is untested. 459e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 469e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To use edge-detection IRQ support, pass the IRQs of both ASICS (for the 479e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96 channel version) or just 1 ASIC (for 48-channel version). Then, use 489e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * comedi_commands with TRIG_NOW. Your callback will be called each time an 499e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * edge is triggered, and the data values will be two sample_t's, which 509e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * should be concatenated to form one 32-bit unsigned int. This value is 519e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the mask of channels that had edges detected from your channel list. Note 529e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * that the bits positions in the mask correspond to positions in your 539e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chanlist when you specified the command and *not* channel id's! 549e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 559e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To set the polarity of the edge-detection interrupts pass a nonzero value 569e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for 579e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * both CR_RANGE and CR_AREF if you want edge-down polarity. 589e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 599e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 48-channel version: 609e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 619e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * On subdev 0, the first 24 channels channels are edge-detect channels. 629e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 639e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 96-channel board you have the following channels that can do edge 649e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * detection: 659e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 669e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 0, channels 0-24 (first 24 channels of 1st ASIC) 679e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) 689e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 699e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Configuration Options: 709e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [0] - I/O port base address 719e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [1] - IRQ (for first ASIC, or first 24 channels) 729e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [2] - IRQ (for second ASIC, pcmuio96 only - IRQ for chans 48-72 739e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * can be the same as first irq!) 749e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */ 756baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7625436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h> 775a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 786baef150380d561a4d695a6be4fc509821c23611Calin Culianu 79f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "../comedidev.h" 8033782dd5edf8db3cdb7c81a3523bf743dd0209b7H Hartley Sweeten 81f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "comedi_fc.h" 826baef150380d561a4d695a6be4fc509821c23611Calin Culianu 83f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten/* 84f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * Register I/O map 85f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 86f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * Offset Page 0 Page 1 Page 2 Page 3 87f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * ------ ----------- ----------- ----------- ----------- 88f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x00 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O 89f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x01 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O 90f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x02 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O 91f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x03 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O 92f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x04 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O 93f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x05 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O 94f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x06 INT_PENDING INT_PENDING INT_PENDING INT_PENDING 95f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x07 Page/Lock Page/Lock Page/Lock Page/Lock 96f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x08 N/A POL_0 ENAB_0 INT_ID0 97f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x09 N/A POL_1 ENAB_1 INT_ID1 98f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * 0x0a N/A POL_2 ENAB_2 INT_ID2 99f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten */ 100f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PORT_REG(x) (0x00 + (x)) 101f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_INT_PENDING_REG 0x06 102f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_LOCK_REG 0x07 103f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_LOCK_PORT(x) ((1 << (x)) & 0x3f) 104f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE(x) (((x) & 0x3) << 6) 105f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_MASK PCMUIO_PAGE(3) 106f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_POL 1 107f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_ENAB 2 108f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_INT_ID 3 109f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_REG(x) (0x08 + (x)) 110f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten 111288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_PORT 8 112288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_ASIC 6 113288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_PORTS_PER_ASIC 3 114288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* number of channels per comedi subdevice */ 115288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_CHANS_PER_SUBDEV 24 116288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV / CHANS_PER_PORT) 117288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_ASIC (CHANS_PER_PORT * PORTS_PER_ASIC) 118288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_CHANS_PER_ASIC 24 119288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC / CHANS_PER_PORT) 120288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_DIO_CHANS (PORTS_PER_ASIC * 2 * CHANS_PER_PORT) 121288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_ASICS (MAX_DIO_CHANS / CHANS_PER_ASIC) 1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu 123288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* IO Memory sizes */ 124288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define ASIC_IOSIZE 0x10 125288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO48_IOSIZE ASIC_IOSIZE 126288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO96_IOSIZE (ASIC_IOSIZE * 2) 1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu 12870a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board { 1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu const char *name; 1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_asics; 13170a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton}; 1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu 133fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = { 134fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten { 135fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten .name = "pcmuio48", 136fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten .num_asics = 1, 137fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten }, { 138fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten .name = "pcmuio96", 139fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten .num_asics = 2, 140fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten }, 141fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten}; 142fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten 143e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private { 1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The below is only used for intr subdevices */ 1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 146365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten /* if non-negative, this subdev has an interrupt asic */ 147365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten int asic; 148365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten /* 149365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * subdev-relative channel mask for channels 150365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * we are interested in 151365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten */ 152365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten int enabled_mask; 1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu int active; 1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu int stop_count; 1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu int continuous; 1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu } intr; 158e15849e54405152087cd343437747db8d931fcd7Bill Pemberton}; 1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu 160055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private { 1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int irq; 1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu } asics[MAX_ASICS]; 165e15849e54405152087cd343437747db8d931fcd7Bill Pemberton struct pcmuio_subdev_private *sprivs; 166055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton}; 1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu 168e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweetenstatic void pcmuio_write(struct comedi_device *dev, unsigned int val, 169e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten int asic, int page, int port) 170e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten{ 171e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); 172e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten 173e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten if (page == 0) { 174e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten /* Port registers are valid for any page */ 175e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0)); 176e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb((val >> 8) & 0xff, iobase + PCMUIO_PORT_REG(port + 1)); 177e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb((val >> 16) & 0xff, iobase + PCMUIO_PORT_REG(port + 2)); 178e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten } else { 179e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG); 180e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb(val & 0xff, iobase + PCMUIO_PAGE_REG(0)); 181e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1)); 182e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2)); 183e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten } 184e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten} 185e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten 1860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev, 1870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s, 1880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_insn *insn, unsigned int *data) 1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 190c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int asic = s->index / 2; 191c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int port = (s->index % 2) ? 3 : 0; 192c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); 1936baef150380d561a4d695a6be4fc509821c23611Calin Culianu int byte_no; 1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 1966baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 0 means this channel was high 1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu writine a 0 sets the channel high 1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 1 means this channel was low 1996baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 means set this channel low 2006baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2016baef150380d561a4d695a6be4fc509821c23611Calin Culianu Therefore everything is always inverted. */ 2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2036baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The insn data is a mask in data[0] and the new data 2046baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in data[1], each channel cooresponding to a bit. */ 2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state = 0; 2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { 209c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten /* bit offset of port in 32-bit doubleword */ 210c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten unsigned long offset = byte_no * 8; 2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this 8-bit port's data */ 2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte = 0, 2130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* The write mask for this port (if any) */ 2140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral write_mask_byte = (data[0] >> offset) & 0xff, 2150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* The data byte for this port */ 2160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral data_byte = (data[1] >> offset) & 0xff; 2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu 218c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no)); 2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (write_mask_byte) { 221365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten byte &= ~write_mask_byte; 222365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten byte |= ~data_byte & write_mask_byte; 223c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no)); 2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save the digital input lines for this byte.. */ 2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state |= ((unsigned int)byte) << offset; 2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now return the DIO lines to data[1] - note they came inverted! */ 2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = ~s->state; 2316baef150380d561a4d695a6be4fc509821c23611Calin Culianu 232a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten return insn->n; 2336baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev, 2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s, 2370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_insn *insn, unsigned int *data) 2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 239c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int asic = s->index / 2; 240c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int port = (s->index % 2) ? 3 : 0; 241c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); 242c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten unsigned int chan = CR_CHAN(insn->chanspec); 243c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int byte_no = chan / 8; 244c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten int bit_no = chan % 8; 2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte; 2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 0 an IO channel's bit sets the channel to INPUT 2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu and pulls the line high as well 2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 to an IO channel's bit pulls the line low 2526baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2536baef150380d561a4d695a6be4fc509821c23611Calin Culianu All channels are implicitly always in OUTPUT mode -- but when 2546baef150380d561a4d695a6be4fc509821c23611Calin Culianu they are high they can be considered to be in INPUT mode.. 2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2566baef150380d561a4d695a6be4fc509821c23611Calin Culianu Thus, we only force channels low if the config request was INPUT, 2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu otherwise we do nothing to the hardware. */ 2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2596baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (data[0]) { 2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_OUTPUT: 2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits -- don't actually do anything since 2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu all input channels are also output channels... */ 2636baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits |= 1 << chan; 2646baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_INPUT: 2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* write a 0 to the actual register representing the channel 2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu to set it to 'input'. 0 means "float high". */ 268c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no)); 2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte &= ~(1 << bit_no); 2706baef150380d561a4d695a6be4fc509821c23611Calin Culianu /**< set input channel to '0' */ 2716baef150380d561a4d695a6be4fc509821c23611Calin Culianu 272365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten /* 273365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * write out byte 274365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * This is the only time we actually affect the hardware 275365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * as all channels are implicitly output -- but input 276365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten * channels are set to float-high. 277365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten */ 278c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no)); 2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2806baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits */ 2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits &= ~(1 << chan); 2826baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_QUERY: 28525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* retrieve from shadow register */ 2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = 2870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void switch_page(struct comedi_device *dev, int asic, int page) 3006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 30146317da71ee85dccc351735e8b463123f4d448a3H Hartley Sweeten outb(PCMUIO_PAGE(page), 302f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten dev->iobase + ASIC_IOSIZE * asic + PCMUIO_PAGE_LOCK_REG); 3036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 3046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 305da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev) 306e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten{ 307a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic; 3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu 310a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten for (asic = 0; asic < board->num_asics; ++asic) { 3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* first, clear all the DIO port bits */ 312e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, 0, 0); 313e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, 0, 3); 3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Next, clear all the paged registers for each page */ 316e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, PCMUIO_PAGE_POL, 0); 317e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); 318e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); 3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev, 3236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten struct comedi_subdevice *s) 3246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 3258099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 326e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten int asic; 3276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 3286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten asic = subpriv->intr.asic; 3296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (asic < 0) 3306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return; /* not an interrupt subdev */ 3316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 3326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.enabled_mask = 0; 3336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.active = 0; 334920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten s->async->inttrig = NULL; 335e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten 336e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten /* disable all intrs for this subdev.. */ 337e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); 3386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 3396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 3403b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic void pcmuio_handle_intr_subdev(struct comedi_device *dev, 3413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_subdevice *s, 3423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned triggered) 3433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{ 3443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 3453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int len = s->async->cmd.chanlist_len; 3463b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned oldevents = s->async->events; 3473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int val = 0; 3483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned long flags; 3493b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned mytrig; 3503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int i; 3513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_lock_irqsave(&subpriv->intr.spinlock, flags); 3533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!subpriv->intr.active) 3553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten goto done; 3563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 35743d70ce9ac772647baf8aadef1aa0f071bfe7f36H Hartley Sweeten mytrig = triggered; 358dbe9c7929c6c0021414d61f85fe4e2f20f069e1cH Hartley Sweeten mytrig &= ((0x1 << s->n_chan) - 1); 3593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!(mytrig & subpriv->intr.enabled_mask)) 3613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten goto done; 3623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < len; i++) { 3643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]); 3653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (mytrig & (1U << chan)) 3663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten val |= (1U << i); 3673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 3683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Write the scan to the buffer. */ 3703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (comedi_buf_put(s->async, ((short *)&val)[0]) && 3713b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten comedi_buf_put(s->async, ((short *)&val)[1])) { 3723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); 3733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } else { 3743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Overflow! Stop acquisition!! */ 3753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 3763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_stop_intr(dev, s); 3773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 3783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Check for end of acquisition. */ 3803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!subpriv->intr.continuous) { 3813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* stop_src == TRIG_COUNT */ 3823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.stop_count > 0) { 3833b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten subpriv->intr.stop_count--; 3843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.stop_count == 0) { 3853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s->async->events |= COMEDI_CB_EOA; 3863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 3873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_stop_intr(dev, s); 3883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 3893b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 3903b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 3913b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3923b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetendone: 3933b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 3943b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3953b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (oldevents != s->async->events) 3963b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten comedi_event(dev, s); 3973b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten} 3983b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 3993b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) 4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 4019a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 4028099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv; 403021314f82405594344b857e13e0493e11dad7298H Hartley Sweeten unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); 4043b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned triggered = 0; 4053b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int got1 = 0; 4063b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned long flags; 4073b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned char int_pend; 40868720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten int i; 4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4103b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); 4113b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 412f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; 4133b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (int_pend) { 4143b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < INTR_PORTS_PER_ASIC; ++i) { 4153b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (int_pend & (0x1 << i)) { 4163b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned char val; 4173b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 418f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten switch_page(dev, asic, PCMUIO_PAGE_INT_ID); 419f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten val = inb(iobase + PCMUIO_PAGE_REG(i)); 4203b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (val) 4213b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* clear pending interrupt */ 422f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten outb(0, iobase + PCMUIO_PAGE_REG(i)); 4233b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4243b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten triggered |= (val << (i * 8)); 4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4263b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4276baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4283b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten ++got1; 4293b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4303b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4313b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); 4323b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4333b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (triggered) { 4343b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_subdevice *s; 4353b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO here: dispatch io lines to subdevs with commands.. */ 4363b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < dev->n_subdevices; i++) { 4373b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s = &dev->subdevices[i]; 4383b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten subpriv = s->private; 4393b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.asic == asic) { 4403b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* 4413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten * This is an interrupt subdev, and it 4423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten * matches this asic! 4433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten */ 4443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_handle_intr_subdev(dev, s, 4453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten triggered); 4466baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4493b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten return got1; 4503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten} 4513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic irqreturn_t interrupt_pcmuio(int irq, void *d) 4533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{ 4543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_device *dev = d; 4553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 4563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int got1 = 0; 4573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int asic; 4586baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (asic = 0; asic < MAX_ASICS; ++asic) { 4603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (irq == devpriv->asics[asic].irq) { 4613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* it is an interrupt for ASIC #asic */ 4623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (pcmuio_handle_asic_interrupt(dev, asic)) 4633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten got1++; 4646baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4656baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4666baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!got1) 4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_NONE; /* interrupt from other source */ 4686baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_HANDLED; 4696baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev, 4720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s) 4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 4748099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 4759a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten 4766baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { 4776baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* An empty acquisition! */ 4786baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events |= COMEDI_CB_EOA; 4796baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 4816baef150380d561a4d695a6be4fc509821c23611Calin Culianu } else { 4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned bits = 0, pol_bits = 0, n; 483e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten int asic; 484ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu 486c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton asic = subpriv->intr.asic; 487c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton if (asic < 0) 4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; /* not an interrupt 4896baef150380d561a4d695a6be4fc509821c23611Calin Culianu subdev */ 4906baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = 0; 4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->chanlist) { 4936baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (n = 0; n < cmd->chanlist_len; n++) { 4946baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits |= (1U << CR_CHAN(cmd->chanlist[n])); 4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu pol_bits |= (CR_AREF(cmd->chanlist[n]) 4960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral || CR_RANGE(cmd-> 4970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral chanlist[n]) ? 1U : 0U) 4980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral << CR_CHAN(cmd->chanlist[n]); 4996baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5006baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 501dbe9c7929c6c0021414d61f85fe4e2f20f069e1cH Hartley Sweeten bits &= ((0x1 << s->n_chan) - 1); 5026baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = bits; 5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu 504e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten /* set pol and enab intrs for this subdev.. */ 505e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); 506e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); 5076baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5086baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 5096baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5106baef150380d561a4d695a6be4fc509821c23611Calin Culianu 511da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5138099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 5146baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5165f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 5176baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.active) 5186baef150380d561a4d695a6be4fc509821c23611Calin Culianu pcmuio_stop_intr(dev, s); 5195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5216baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5246baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. 5266baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 5276baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int 528da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, 5290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int trignum) 5306baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5318099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 5326baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 5336baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 5346baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5356baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (trignum != 0) 5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5385f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 539920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten s->async->inttrig = NULL; 5400389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (subpriv->intr.active) 5416baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 5420389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya 5435f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 5446baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5450389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (event) 5466baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5486baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 5496baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5516baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 5526baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice. 5536baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 554da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 5556baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5568099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 557ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 5586baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 5596baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 5606baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5615f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 5636baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5646baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up end of acquisition. */ 5656baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->stop_src) { 5666baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_COUNT: 5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 0; 5686baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = cmd->stop_arg; 5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NONE */ 5726baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 1; 5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = 0; 5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up start of acquisition. */ 5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->start_src) { 5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_INT: 5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->inttrig = pcmuio_inttrig_start_intr; 5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NOW */ 5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 5856baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5875f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5890389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (event) 5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu 595f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev, 596f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten struct comedi_subdevice *s, 597f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten struct comedi_cmd *cmd) 5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 599f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten int err = 0; 600f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 601f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 1 : check if triggers are trivially valid */ 602f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 603f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); 604f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); 605f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); 606f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 607f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 608f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 609f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 610f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 1; 611f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 612f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 2a : make sure trigger sources are unique */ 613f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 614f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_is_unique(cmd->start_src); 615f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_is_unique(cmd->stop_src); 616f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 617f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 2b : and mutually compatible */ 618f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 619f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 620f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 2; 621f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 622f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 3: check if arguments are trivially valid */ 623f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 624f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 625f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 626f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 627f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 628f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 629f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten switch (cmd->stop_src) { 630f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten case TRIG_COUNT: 631f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* any count allowed */ 632f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 633f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten case TRIG_NONE: 634f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 635f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 636f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten default: 637f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 638f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten } 639f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 640f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 641f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 3; 642f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 643f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* step 4: fix up any arguments */ 644f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 645f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* if (err) return 4; */ 646f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 647f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 0; 6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) 6516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 652a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 6536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten struct comedi_subdevice *s; 6548099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_private *devpriv; 6558099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv; 6561699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten int sdev_no, n_subdevs, asic; 6576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten unsigned int irq[MAX_ASICS]; 6588b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten int ret; 6596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 6606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[0] = it->options[1]; 6616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[1] = it->options[2]; 6626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 66335626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten ret = comedi_request_region(dev, it->options[0], 66435626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten board->num_asics * ASIC_IOSIZE); 66535626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten if (ret) 66635626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten return ret; 6676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 668c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); 669c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten if (!devpriv) 670c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten return -ENOMEM; 671c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten dev->private = devpriv; 6726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 673021314f82405594344b857e13e0493e11dad7298H Hartley Sweeten for (asic = 0; asic < MAX_ASICS; ++asic) 6746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten spin_lock_init(&devpriv->asics[asic].spinlock); 6756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 676c87e1f26054388b661298a61e906a03fa2cd193eH Hartley Sweeten n_subdevs = board->num_asics * 2; 67778110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches devpriv->sprivs = kcalloc(n_subdevs, 67878110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches sizeof(struct pcmuio_subdev_private), 67978110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches GFP_KERNEL); 68078110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches if (!devpriv->sprivs) 6816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return -ENOMEM; 682eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten 6838b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten ret = comedi_alloc_subdevices(dev, n_subdevs); 6848b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten if (ret) 6858b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten return ret; 6866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 6876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { 68868720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten s = &dev->subdevices[sdev_no]; 6898099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten subpriv = &devpriv->sprivs[sdev_no]; 6908099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten s->private = subpriv; 6916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->maxdata = 1; 6926b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->range_table = &range_digital; 6936b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 6946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->type = COMEDI_SUBD_DIO; 6956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->insn_bits = pcmuio_dio_insn_bits; 6966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->insn_config = pcmuio_dio_insn_config; 697c87e1f26054388b661298a61e906a03fa2cd193eH Hartley Sweeten s->n_chan = 24; 6986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 6991699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten /* subdevices 0 and 2 suppport interrupts */ 7001699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten if ((sdev_no % 2) == 0) { 7011699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten /* setup the interrupt subdevice */ 7021699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten subpriv->intr.asic = sdev_no / 2; 7031699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten dev->read_subdev = s; 7041699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->subdev_flags |= SDF_CMD_READ; 7051699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->cancel = pcmuio_cancel; 7061699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->do_cmd = pcmuio_cmd; 7071699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->do_cmdtest = pcmuio_cmdtest; 7081699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->len_chanlist = s->n_chan; 7091699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten } else { 7101699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten subpriv->intr.asic = -1; 7111699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten s->len_chanlist = 1; 7126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten spin_lock_init(&subpriv->intr.spinlock); 7146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten init_asics(dev); /* clear out all the registers, basically */ 7176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { 7196b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (irq[asic] 7206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten && request_irq(irq[asic], interrupt_pcmuio, 721a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten IRQF_SHARED, board->name, dev)) { 7226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int i; 7236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* unroll the allocated irqs.. */ 7246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (i = asic - 1; i >= 0; --i) { 7256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten free_irq(irq[i], dev); 7266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[i].irq = irq[i] = 0; 7276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[asic] = 0; 7296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].irq = irq[asic]; 7316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (irq[0]) { 734f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "irq: %u\n", irq[0]); 735a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten if (irq[1] && board->num_asics == 2) 736f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "second ASIC irq: %u\n", 737f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott irq[1]); 7386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } else { 739f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "(IRQ mode disabled)\n"); 7406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return 1; 7446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 7456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 746484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev) 7476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 7489a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 7496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int i; 7506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (i = 0; i < MAX_ASICS; ++i) { 7526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (devpriv->asics[i].irq) 7536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten free_irq(devpriv->asics[i].irq, dev); 7546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 7556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (devpriv && devpriv->sprivs) 7566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten kfree(devpriv->sprivs); 757a32c6d0084992d3e58a93120c9ce9527e80c651eH Hartley Sweeten comedi_legacy_detach(dev); 7586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 7596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 760294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = { 7616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .driver_name = "pcmuio", 7626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .module = THIS_MODULE, 7636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .attach = pcmuio_attach, 7646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .detach = pcmuio_detach, 7656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .board_name = &pcmuio_boards[0].name, 7666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .offset = sizeof(struct pcmuio_board), 7676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_names = ARRAY_SIZE(pcmuio_boards), 7686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}; 769294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver); 77090f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas 77190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org"); 77290f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver"); 77390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL"); 774