pcmuio.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 26baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi/drivers/pcmuio.c 36baef150380d561a4d695a6be4fc509821c23611Calin Culianu Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards. 46baef150380d561a4d695a6be4fc509821c23611Calin Culianu 56baef150380d561a4d695a6be4fc509821c23611Calin Culianu COMEDI - Linux Control and Measurement Device Interface 66baef150380d561a4d695a6be4fc509821c23611Calin Culianu Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> 76baef150380d561a4d695a6be4fc509821c23611Calin Culianu 86baef150380d561a4d695a6be4fc509821c23611Calin Culianu This program is free software; you can redistribute it and/or modify 96baef150380d561a4d695a6be4fc509821c23611Calin Culianu it under the terms of the GNU General Public License as published by 106baef150380d561a4d695a6be4fc509821c23611Calin Culianu the Free Software Foundation; either version 2 of the License, or 116baef150380d561a4d695a6be4fc509821c23611Calin Culianu (at your option) any later version. 126baef150380d561a4d695a6be4fc509821c23611Calin Culianu 136baef150380d561a4d695a6be4fc509821c23611Calin Culianu This program is distributed in the hope that it will be useful, 146baef150380d561a4d695a6be4fc509821c23611Calin Culianu but WITHOUT ANY WARRANTY; without even the implied warranty of 156baef150380d561a4d695a6be4fc509821c23611Calin Culianu MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 166baef150380d561a4d695a6be4fc509821c23611Calin Culianu GNU General Public License for more details. 176baef150380d561a4d695a6be4fc509821c23611Calin Culianu 186baef150380d561a4d695a6be4fc509821c23611Calin Culianu You should have received a copy of the GNU General Public License 196baef150380d561a4d695a6be4fc509821c23611Calin Culianu along with this program; if not, write to the Free Software 206baef150380d561a4d695a6be4fc509821c23611Calin Culianu Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 216baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/ 226baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 236baef150380d561a4d695a6be4fc509821c23611Calin CulianuDriver: pcmuio 246baef150380d561a4d695a6be4fc509821c23611Calin CulianuDescription: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems. 256baef150380d561a4d695a6be4fc509821c23611Calin CulianuDevices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96) 266baef150380d561a4d695a6be4fc509821c23611Calin CulianuAuthor: Calin Culianu <calin@ajvar.org> 276baef150380d561a4d695a6be4fc509821c23611Calin CulianuUpdated: Fri, 13 Jan 2006 12:01:01 -0500 286baef150380d561a4d695a6be4fc509821c23611Calin CulianuStatus: works 296baef150380d561a4d695a6be4fc509821c23611Calin Culianu 306baef150380d561a4d695a6be4fc509821c23611Calin CulianuA driver for the relatively straightforward-to-program PCM-UIO48A and 316baef150380d561a4d695a6be4fc509821c23611Calin CulianuPCM-UIO96A boards from Winsystems. These boards use either one or two 326baef150380d561a4d695a6be4fc509821c23611Calin Culianu(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). 336baef150380d561a4d695a6be4fc509821c23611Calin CulianuThis chip is interesting in that each I/O line is individually 346baef150380d561a4d695a6be4fc509821c23611Calin Culianuprogrammable for INPUT or OUTPUT (thus comedi_dio_config can be done 356baef150380d561a4d695a6be4fc509821c23611Calin Culianuon a per-channel basis). Also, each chip supports edge-triggered 366baef150380d561a4d695a6be4fc509821c23611Calin Culianuinterrupts for the first 24 I/O lines. Of course, since the 376baef150380d561a4d695a6be4fc509821c23611Calin Culianu96-channel version of the board has two ASICs, it can detect polarity 386baef150380d561a4d695a6be4fc509821c23611Calin Culianuchanges on up to 48 I/O lines. Since this is essentially an (non-PnP) 396baef150380d561a4d695a6be4fc509821c23611Calin CulianuISA board, I/O Address and IRQ selection are done through jumpers on 406baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe board. You need to pass that information to this driver as the 416baef150380d561a4d695a6be4fc509821c23611Calin Culianufirst and second comedi_config option, respectively. Note that the 426baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel version uses 16 bytes of IO memory and the 96-channel 436baef150380d561a4d695a6be4fc509821c23611Calin Culianuversion uses 32-bytes (in case you are worried about conflicts). The 446baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel board is split into two 24-channel comedi subdevices. 456baef150380d561a4d695a6be4fc509821c23611Calin CulianuThe 96-channel board is split into 4 24-channel DIO subdevices. 466baef150380d561a4d695a6be4fc509821c23611Calin Culianu 476baef150380d561a4d695a6be4fc509821c23611Calin CulianuNote that IRQ support has been added, but it is untested. 486baef150380d561a4d695a6be4fc509821c23611Calin Culianu 496baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo use edge-detection IRQ support, pass the IRQs of both ASICS 506baef150380d561a4d695a6be4fc509821c23611Calin Culianu(for the 96 channel version) or just 1 ASIC (for 48-channel version). 516baef150380d561a4d695a6be4fc509821c23611Calin CulianuThen, use use comedi_commands with TRIG_NOW. 526baef150380d561a4d695a6be4fc509821c23611Calin CulianuYour callback will be called each time an edge is triggered, and the data 536baef150380d561a4d695a6be4fc509821c23611Calin Culianuvalues will be two sample_t's, which should be concatenated to form one 546baef150380d561a4d695a6be4fc509821c23611Calin Culianu32-bit unsigned int. This value is the mask of channels that had 556baef150380d561a4d695a6be4fc509821c23611Calin Culianuedges detected from your channel list. Note that the bits positions 566baef150380d561a4d695a6be4fc509821c23611Calin Culianuin the mask correspond to positions in your chanlist when you specified 576baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe command and *not* channel id's! 586baef150380d561a4d695a6be4fc509821c23611Calin Culianu 596baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo set the polarity of the edge-detection interrupts pass a nonzero value for 606baef150380d561a4d695a6be4fc509821c23611Calin Culianueither CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both 616baef150380d561a4d695a6be4fc509821c23611Calin CulianuCR_RANGE and CR_AREF if you want edge-down polarity. 626baef150380d561a4d695a6be4fc509821c23611Calin Culianu 636baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 48-channel version: 646baef150380d561a4d695a6be4fc509821c23611Calin Culianu 656baef150380d561a4d695a6be4fc509821c23611Calin CulianuOn subdev 0, the first 24 channels channels are edge-detect channels. 666baef150380d561a4d695a6be4fc509821c23611Calin Culianu 676baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 96-channel board you have the collowing channels that can do edge detection: 686baef150380d561a4d695a6be4fc509821c23611Calin Culianu 696baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 0, channels 0-24 (first 24 channels of 1st ASIC) 706baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 2, channels 0-24 (first 24 channels of 2nd ASIC) 716baef150380d561a4d695a6be4fc509821c23611Calin Culianu 726baef150380d561a4d695a6be4fc509821c23611Calin CulianuConfiguration Options: 736baef150380d561a4d695a6be4fc509821c23611Calin Culianu [0] - I/O port base address 746baef150380d561a4d695a6be4fc509821c23611Calin Culianu [1] - IRQ (for first ASIC, or first 24 channels) 756baef150380d561a4d695a6be4fc509821c23611Calin Culianu [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!) 766baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/ 776baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7825436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h> 796baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include "../comedidev.h" 806baef150380d561a4d695a6be4fc509821c23611Calin Culianu 816baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include <linux/pci.h> /* for PCI devices */ 826baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8353106ae68acf6eda9593150a25fc44e30fd5ff68Bill Pemberton#define MIN(a, b) (((a) < (b)) ? (a) : (b)) 846baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT 8 856baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC 6 866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC 3 876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ 886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) 896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) 906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24 916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) 926baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT) 936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) 946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define SDEV_NO ((int)(s - dev->subdevices)) 956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) 966baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */ 976baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x10) 986baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO48_IOSIZE ASIC_IOSIZE 996baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2) 1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from 1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu the base address. Note that there is a paging scheme to swap out 1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu offsets 0x8-0xA using the PAGELOCK register. See the table below. 1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu Register(s) Pages R/W? Description 1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu -------------------------------------------------------------- 1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_PORTx All R/W Read/Write/Configure IO 1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. 1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_PAGELOCK All WriteOnly Select a page 1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity 1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. 1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. 1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0 1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1 1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2 1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3 1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4 1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5 1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6 1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page 1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu and bits 0-5 are used to 'lock down' a particular 1236baef150380d561a4d695a6be4fc509821c23611Calin Culianu port above to make it readonly. */ 1246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8 1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9 1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA 1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8 1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9 1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA 1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8 1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9 1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA 1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3 1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4 1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8 1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6 1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0 1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) 1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_MASK ~(REG_PAGE_MASK) 1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1 1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2 1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3 1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 1466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards. Describing the 1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent. 1486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not. 1496baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 15070a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board { 1516baef150380d561a4d695a6be4fc509821c23611Calin Culianu const char *name; 1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_asics; 1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_channels_per_port; 1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_ports; 15570a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton}; 1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu 15770a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstatic const struct pcmuio_board pcmuio_boards[] = { 1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu { 15968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .name = "pcmuio48", 16068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .num_asics = 1, 16168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .num_ports = 6, 1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu }, 1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu { 16468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .name = "pcmuio96", 16568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .num_asics = 2, 16668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .num_ports = 12, 1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu }, 1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu}; 1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Useful for shorthand access to the particular board structure 1726baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 17370a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton#define thisboard ((const struct pcmuio_board *)dev->board_ptr) 1746baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1756baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice. */ 176e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private { 1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* mapping of halfwords (bytes) in port/chanarray to iobase */ 1786baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobases[PORTS_PER_SUBDEV]; 1796baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1806baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The below is only used for intr subdevices */ 1816baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 1826baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic; /* if non-negative, this subdev has an interrupt asic */ 1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu int first_chan; /* if nonnegative, the first channel id for 1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu interrupts. */ 1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu int num_asic_chans; /* the number of asic channels in this subdev 1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu that have interrutps */ 1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic_chan; /* if nonnegative, the first channel id with 1886baef150380d561a4d695a6be4fc509821c23611Calin Culianu respect to the asic that has interrupts */ 1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu int enabled_mask; /* subdev-relative channel mask for channels 1906baef150380d561a4d695a6be4fc509821c23611Calin Culianu we are interested in */ 1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu int active; 1926baef150380d561a4d695a6be4fc509821c23611Calin Culianu int stop_count; 1936baef150380d561a4d695a6be4fc509821c23611Calin Culianu int continuous; 1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu } intr; 196e15849e54405152087cd343437747db8d931fcd7Bill Pemberton}; 1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver. If 1996baef150380d561a4d695a6be4fc509821c23611Calin Culianu several hardware drivers keep similar information in this structure, 20071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton feel free to suggest moving the variable to the struct comedi_device struct. */ 201055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private { 2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 2036baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char pagelock; /* current page and lock */ 2046baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */ 2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */ 2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu int num; 2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobase; 2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int irq; 2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu } asics[MAX_ASICS]; 211e15849e54405152087cd343437747db8d931fcd7Bill Pemberton struct pcmuio_subdev_private *sprivs; 212055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton}; 2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu * most drivers define the following macro to make it easy to 2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu * access the private structure. 2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 218055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton#define devpriv ((struct pcmuio_private *)dev->private) 219e15849e54405152087cd343437747db8d931fcd7Bill Pemberton#define subpriv ((struct pcmuio_subdev_private *)s->private) 2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 221139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module 2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu * which functions to call to configure/deconfigure (attach/detach) 2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the board, and also about the kernel module that contains 2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the device code. 2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 226da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it); 227da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_detach(struct comedi_device *dev); 2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu 229139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver = { 23068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .driver_name = "pcmuio", 23168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .module = THIS_MODULE, 23268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .attach = pcmuio_attach, 23368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .detach = pcmuio_detach, 2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* It is not necessary to implement the following members if you are 2356baef150380d561a4d695a6be4fc509821c23611Calin Culianu * writing a driver for a ISA PnP or PCI card */ 2366baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Most drivers will support multiple types of boards by 2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu * having an array of board structures. These were defined 2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in pcmuio_boards[] above. Note that the element 'name' 2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu * was first in the structure -- Comedi uses this fact to 2406baef150380d561a4d695a6be4fc509821c23611Calin Culianu * extract the name of the board without knowing any details 2416baef150380d561a4d695a6be4fc509821c23611Calin Culianu * about the structure except for its length. 2426baef150380d561a4d695a6be4fc509821c23611Calin Culianu * When a device is attached (by comedi_config), the name 2436baef150380d561a4d695a6be4fc509821c23611Calin Culianu * of the device is given to Comedi, and Comedi tries to 2446baef150380d561a4d695a6be4fc509821c23611Calin Culianu * match it by going through the list of board names. If 2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu * there is a match, the address of the pointer is put 2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * into dev->board_ptr and driver->attach() is called. 2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Note that these are not necessary if you can determine 2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the type of board in software. ISA PnP, PCI, and PCMCIA 2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu * devices are such boards. 2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 25268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .board_name = &pcmuio_boards[0].name, 25368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton .offset = sizeof(struct pcmuio_board), 2548629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton .num_names = ARRAY_SIZE(pcmuio_boards), 2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu}; 2566baef150380d561a4d695a6be4fc509821c23611Calin Culianu 257814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 258814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pemberton struct comedi_insn *insn, unsigned int *data); 259814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, 260814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pemberton struct comedi_insn *insn, unsigned int *data); 2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu 26270265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t interrupt_pcmuio(int irq, void *d); 26334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *); 264814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 265814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); 266814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 267814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pemberton struct comedi_cmd *cmd); 2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* some helper functions to deal with specifics of this device's registers */ 270814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */ 271814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void switch_page(struct comedi_device *dev, int asic, int page); 2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused 273814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port); 274814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port); 2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 2786baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Attach is called by the Comedi core to configure the driver 2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu * for a particular board. If you specified a board_name array 2806baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in the driver structure, dev->board_ptr contains that 2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu * address. 2826baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 283da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) 2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 28534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; 2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobase; 2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int irq[MAX_ASICS]; 2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu iobase = it->options[0]; 2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu irq[0] = it->options[1]; 2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu irq[1] = it->options[2]; 2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, 2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu iobase); 2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->iobase = iobase; 2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!iobase || !request_region(iobase, 3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu thisboard->num_asics * ASIC_IOSIZE, 3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu driver.driver_name)) { 3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("I/O port conflict\n"); 3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EIO; 3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Initialize dev->board_name. Note that we can use the "thisboard" 3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu * macro now, since we just initialized it in the last line. 3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->board_name = thisboard->name; 3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Allocate the private structure area. alloc_private() is a 3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu * convenient macro defined in comedidev.h. 3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 316055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) { 3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("cannot allocate private data structure\n"); 3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -ENOMEM; 3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (asic = 0; asic < MAX_ASICS; ++asic) { 3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].num = asic; 3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; 3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].irq = 0; /* this gets actually set at the end of 3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu this function when we 3265f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman request_irqs */ 3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu spin_lock_init(&devpriv->asics[asic].spinlock); 3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3306baef150380d561a4d695a6be4fc509821c23611Calin Culianu chans_left = CHANS_PER_ASIC * thisboard->num_asics; 3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu n_subdevs = CALC_N_SUBDEVS(chans_left); 3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->sprivs = 333e15849e54405152087cd343437747db8d931fcd7Bill Pemberton kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), GFP_KERNEL); 3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!devpriv->sprivs) { 3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("cannot allocate subdevice private data structures\n"); 3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -ENOMEM; 3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3386baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* 3396baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Allocate the subdevice structures. alloc_subdevice() is a 3406baef150380d561a4d695a6be4fc509821c23611Calin Culianu * convenient macro defined in comedidev.h. 3416baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 3426baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the 3436baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 96-channel version of the board. 3446baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 3456baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (alloc_subdevices(dev, n_subdevs) < 0) { 3466baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("cannot allocate subdevice data structures\n"); 3476baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -ENOMEM; 3486baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3496baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3506baef150380d561a4d695a6be4fc509821c23611Calin Culianu port = 0; 3516baef150380d561a4d695a6be4fc509821c23611Calin Culianu asic = 0; 3526baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { 3536baef150380d561a4d695a6be4fc509821c23611Calin Culianu int byte_no; 3546baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3556baef150380d561a4d695a6be4fc509821c23611Calin Culianu s = dev->subdevices + sdev_no; 3566baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->private = devpriv->sprivs + sdev_no; 3576baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->maxdata = 1; 3586baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->range_table = &range_digital; 3596baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 3606baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->type = COMEDI_SUBD_DIO; 3616baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->insn_bits = pcmuio_dio_insn_bits; 3626baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->insn_config = pcmuio_dio_insn_config; 3636baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV); 3646baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.asic = -1; 3656baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.first_chan = -1; 3666baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.asic_chan = -1; 3676baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.num_asic_chans = -1; 3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->len_chanlist = 1; 3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save the ioport address for each 'port' of 8 channels in the 3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu subdevice */ 3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { 3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (port >= PORTS_PER_ASIC) { 3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu port = 0; 3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu ++asic; 3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu thisasic_chanct = 0; 3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->iobases[byte_no] = 3806baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].iobase + port; 3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3826baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (thisasic_chanct < 3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu CHANS_PER_PORT * INTR_PORTS_PER_ASIC 3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu && subpriv->intr.asic < 0) { 3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this is an interrupt subdevice, so setup the struct */ 3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.asic = asic; 3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = 0; 3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.first_chan = byte_no * 8; 3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.asic_chan = thisasic_chanct; 3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.num_asic_chans = 3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->n_chan - subpriv->intr.first_chan; 3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->read_subdev = s; 3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->subdev_flags |= SDF_CMD_READ; 3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->cancel = pcmuio_cancel; 3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->do_cmd = pcmuio_cmd; 3976baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->do_cmdtest = pcmuio_cmdtest; 3986baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->len_chanlist = subpriv->intr.num_asic_chans; 3996baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu thisasic_chanct += CHANS_PER_PORT; 4016baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4026baef150380d561a4d695a6be4fc509821c23611Calin Culianu spin_lock_init(&subpriv->intr.spinlock); 4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu chans_left -= s->n_chan; 4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!chans_left) { 4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu asic = 0; /* reset the asic to our first asic, to do intr subdevs */ 4086baef150380d561a4d695a6be4fc509821c23611Calin Culianu port = 0; 4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4106baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4116baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4126baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4136baef150380d561a4d695a6be4fc509821c23611Calin Culianu init_asics(dev); /* clear out all the registers, basically */ 4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4156baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { 4166baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (irq[asic] 4175f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman && request_irq(irq[asic], interrupt_pcmuio, 4186baef150380d561a4d695a6be4fc509821c23611Calin Culianu IRQF_SHARED, thisboard->name, dev)) { 4196baef150380d561a4d695a6be4fc509821c23611Calin Culianu int i; 4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* unroll the allocated irqs.. */ 4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (i = asic - 1; i >= 0; --i) { 4225f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman free_irq(irq[i], dev); 4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[i].irq = irq[i] = 0; 4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu irq[asic] = 0; 4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4276baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].irq = irq[asic]; 4286baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4296baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4306baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple 4316baef150380d561a4d695a6be4fc509821c23611Calin Culianu irqs.. */ 4326baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4336baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (irq[0]) { 4346baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("irq: %u ", irq[0]); 4356baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (irq[1] && thisboard->num_asics == 2) 4366baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("second ASIC irq: %u ", irq[1]); 4376baef150380d561a4d695a6be4fc509821c23611Calin Culianu } else { 4386baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("(IRQ mode disabled) "); 4396baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4406baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4416baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("attached\n"); 4426baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4436baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 4446baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 4456baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4466baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 4476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * _detach is called to deconfigure a device. It should deallocate 4486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * resources. 4496baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This function is also called when _attach() fails, so it should be 4506baef150380d561a4d695a6be4fc509821c23611Calin Culianu * careful not to release resources that were not necessarily 4516baef150380d561a4d695a6be4fc509821c23611Calin Culianu * allocated by _attach(). dev->private and dev->subdevices are 4526baef150380d561a4d695a6be4fc509821c23611Calin Culianu * deallocated automatically by the core. 4536baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 454da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_detach(struct comedi_device *dev) 4556baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 4566baef150380d561a4d695a6be4fc509821c23611Calin Culianu int i; 4576baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4586baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); 4596baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (dev->iobase) 4606baef150380d561a4d695a6be4fc509821c23611Calin Culianu release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics); 4616baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4626baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (i = 0; i < MAX_ASICS; ++i) { 4636baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (devpriv->asics[i].irq) 4645f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman free_irq(devpriv->asics[i].irq, dev); 4656baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 4666baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (devpriv && devpriv->sprivs) 4686baef150380d561a4d695a6be4fc509821c23611Calin Culianu kfree(devpriv->sprivs); 4696baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 4716baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 4726baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special. Although it is possible to 4746baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more 4756baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface. 4766baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels. The 4776baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */ 478da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 479da91b2692e0939b307f9047192d2b9fe07793e7aBill Pemberton struct comedi_insn *insn, unsigned int *data) 4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 4816baef150380d561a4d695a6be4fc509821c23611Calin Culianu int byte_no; 4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (insn->n != 2) 4836baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 4846baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 4866baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 0 means this channel was high 4876baef150380d561a4d695a6be4fc509821c23611Calin Culianu writine a 0 sets the channel high 4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 1 means this channel was low 4896baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 means set this channel low 4906baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu Therefore everything is always inverted. */ 4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4936baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The insn data is a mask in data[0] and the new data 4946baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in data[1], each channel cooresponding to a bit. */ 4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4966baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 4976baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 4986baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("write mask: %08x data: %08x\n", data[0], data[1]); 4996baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 5006baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5016baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state = 0; 5026baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { 5046baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* address of 8-bit port */ 5056baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long ioaddr = subpriv->iobases[byte_no], 5066baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* bit offset of port in 32-bit doubleword */ 5076baef150380d561a4d695a6be4fc509821c23611Calin Culianu offset = byte_no * 8; 5086baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this 8-bit port's data */ 5096baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte = 0, 5106baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The write mask for this port (if any) */ 5116baef150380d561a4d695a6be4fc509821c23611Calin Culianu write_mask_byte = (data[0] >> offset) & 0xff, 5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The data byte for this port */ 5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu data_byte = (data[1] >> offset) & 0xff; 5146baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte = inb(ioaddr); /* read all 8-bits for this port */ 5166baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 5186baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 5196baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte); 5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 5216baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (write_mask_byte) { 5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this byte has some write_bits -- so set the output lines */ 5246baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte &= ~write_mask_byte; /* clear bits for write mask */ 5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */ 5266baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Write out the new digital output state */ 5276baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(byte, ioaddr); 5286baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 5306baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 5316baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("data_out_byte %02x\n", (unsigned)byte); 5326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 5336baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save the digital input lines for this byte.. */ 5346baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state |= ((unsigned int)byte) << offset; 5356baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now return the DIO lines to data[1] - note they came inverted! */ 5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = ~s->state; 5396baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 5416baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 5426baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("s->state %08x data_out %08x\n", s->state, data[1]); 5436baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 5446baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5456baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 2; 5466baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5486baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is 5496baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction. chanspec 5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the 5516baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */ 552da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, 553da91b2692e0939b307f9047192d2b9fe07793e7aBill Pemberton struct comedi_insn *insn, unsigned int *data) 5546baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5556baef150380d561a4d695a6be4fc509821c23611Calin Culianu int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = 5566baef150380d561a4d695a6be4fc509821c23611Calin Culianu chan % 8; 5576baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long ioaddr; 5586baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte; 5596baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5606baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Compute ioaddr for this channel */ 5616baef150380d561a4d695a6be4fc509821c23611Calin Culianu ioaddr = subpriv->iobases[byte_no]; 5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5636baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 5646baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 0 an IO channel's bit sets the channel to INPUT 5656baef150380d561a4d695a6be4fc509821c23611Calin Culianu and pulls the line high as well 5666baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 to an IO channel's bit pulls the line low 5686baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu All channels are implicitly always in OUTPUT mode -- but when 5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu they are high they can be considered to be in INPUT mode.. 5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5726baef150380d561a4d695a6be4fc509821c23611Calin Culianu Thus, we only force channels low if the config request was INPUT, 5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu otherwise we do nothing to the hardware. */ 5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (data[0]) { 5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_OUTPUT: 5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits -- don't actually do anything since 5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu all input channels are also output channels... */ 5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits |= 1 << chan; 5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_INPUT: 5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* write a 0 to the actual register representing the channel 5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu to set it to 'input'. 0 means "float high". */ 5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte = inb(ioaddr); 5856baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte &= ~(1 << bit_no); 5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu /**< set input channel to '0' */ 5876baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* write out byte -- this is the only time we actually affect the 5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu hardware as all channels are implicitly output -- but input 5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu channels are set to float-high */ 5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(byte, ioaddr); 5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits */ 5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits &= ~(1 << chan); 5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_QUERY: 5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* retreive from shadow register */ 5996baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = 6006baef150380d561a4d695a6be4fc509821c23611Calin Culianu (s-> 6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6096baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6106baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6126baef150380d561a4d695a6be4fc509821c23611Calin Culianu 613da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev) 6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ /* sets up an 6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu ASIC chip to defaults */ 6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic; 6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (asic = 0; asic < thisboard->num_asics; ++asic) { 6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu int port, page; 6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE; 6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6226baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, 0); /* switch back to page 0 */ 6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6246baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* first, clear all the DIO port bits */ 6256baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = 0; port < PORTS_PER_ASIC; ++port) 6266baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, baseaddr + REG_PORT0 + port); 6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Next, clear all the paged registers for each page */ 6296baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (page = 1; page < NUM_PAGES; ++page) { 6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu int reg; 6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now clear all the paged registers */ 6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, page); 6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (reg = FIRST_PAGED_REG; 6346baef150380d561a4d695a6be4fc509821c23611Calin Culianu reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) 6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, baseaddr + reg); 6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6376baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6386baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG set rising edge interrupts on port0 of both asics */ 6396baef150380d561a4d695a6be4fc509821c23611Calin Culianu /*switch_page(dev, asic, PAGE_POL); 6406baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0xff, baseaddr + REG_POL0); 6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_ENAB); 6426baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0xff, baseaddr + REG_ENAB0); */ 6436baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* END DEBUG */ 6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6456baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, 0); /* switch back to default page 0 */ 6466baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu 650da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void switch_page(struct comedi_device *dev, int asic, int page) 6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6526baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (asic < 0 || asic >= thisboard->num_asics) 6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* paranoia */ 6546baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (page < 0 || page >= NUM_PAGES) 6556baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* more paranoia */ 6566baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6576baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; 6586baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; 6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6606baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now write out the shadow register */ 6616baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(devpriv->asics[asic].pagelock, 6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6656baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused 666da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port) 6676baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6686baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (asic < 0 || asic >= thisboard->num_asics) 6696baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* paranoia */ 6706baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (port < 0 || port >= PORTS_PER_ASIC) 6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* more paranoia */ 6726baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock |= 0x1 << port; 6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now write out the shadow register */ 6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(devpriv->asics[asic].pagelock, 6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6786baef150380d561a4d695a6be4fc509821c23611Calin Culianu 679da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port) 6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6816baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (asic < 0 || asic >= thisboard->num_asics) 6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* paranoia */ 6836baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (port < 0 || port >= PORTS_PER_ASIC) 6846baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* more paranoia */ 6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; 6866baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now write out the shadow register */ 6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(devpriv->asics[asic].pagelock, 6886baef150380d561a4d695a6be4fc509821c23611Calin Culianu dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */ 6916baef150380d561a4d695a6be4fc509821c23611Calin Culianu 69270265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t interrupt_pcmuio(int irq, void *d) 6936baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic, got1 = 0; 69571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = (struct comedi_device *) d; 6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (asic = 0; asic < MAX_ASICS; ++asic) { 6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (irq == devpriv->asics[asic].irq) { 6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned triggered = 0; 7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobase = devpriv->asics[asic].iobase; 7026baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* it is an interrupt for ASIC #asic */ 7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char int_pend; 7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7055f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); 7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu int_pend = inb(iobase + REG_INT_PENDING) & 0x07; 7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (int_pend) { 7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu int port; 7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = 0; port < INTR_PORTS_PER_ASIC; 7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu ++port) { 7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (int_pend & (0x1 << port)) { 7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char 7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu io_lines_with_edges = 0; 7166baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, 7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu PAGE_INT_ID); 7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu io_lines_with_edges = 7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu inb(iobase + 7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_ID0 + port); 7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (io_lines_with_edges) 7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* clear pending interrupt */ 7246baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, iobase + 7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_ID0 + 7266baef150380d561a4d695a6be4fc509821c23611Calin Culianu port); 7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7286baef150380d561a4d695a6be4fc509821c23611Calin Culianu triggered |= 7296baef150380d561a4d695a6be4fc509821c23611Calin Culianu io_lines_with_edges << 7306baef150380d561a4d695a6be4fc509821c23611Calin Culianu port * 8; 7316baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7326baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7336baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7346baef150380d561a4d695a6be4fc509821c23611Calin Culianu ++got1; 7356baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7366baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7375f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); 7386baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7396baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (triggered) { 74034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 7416baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TODO here: dispatch io lines to subdevs with commands.. */ 7426baef150380d561a4d695a6be4fc509821c23611Calin Culianu printk("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered); 7436baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (s = dev->subdevices; 7446baef150380d561a4d695a6be4fc509821c23611Calin Culianu s < dev->subdevices + dev->n_subdevices; 7456baef150380d561a4d695a6be4fc509821c23611Calin Culianu ++s) { 7466baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */ 7476baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 7486baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned oldevents; 7496baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7505f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave (&subpriv->intr.spinlock, flags); 7516baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7526baef150380d561a4d695a6be4fc509821c23611Calin Culianu oldevents = s->async->events; 7536baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7546baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.active) { 7556baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned mytrig = 7566baef150380d561a4d695a6be4fc509821c23611Calin Culianu ((triggered >> 7576baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv-> 7586baef150380d561a4d695a6be4fc509821c23611Calin Culianu intr. 7596baef150380d561a4d695a6be4fc509821c23611Calin Culianu asic_chan) 7606baef150380d561a4d695a6be4fc509821c23611Calin Culianu & ((0x1 << subpriv->intr.num_asic_chans) - 1)) << subpriv->intr.first_chan; 7616baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (mytrig & subpriv-> 7626baef150380d561a4d695a6be4fc509821c23611Calin Culianu intr. 7636baef150380d561a4d695a6be4fc509821c23611Calin Culianu enabled_mask) { 764790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int val = 7656baef150380d561a4d695a6be4fc509821c23611Calin Culianu 0; 7666baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int n, 7676baef150380d561a4d695a6be4fc509821c23611Calin Culianu ch, len; 7686baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7696baef150380d561a4d695a6be4fc509821c23611Calin Culianu len = s->async-> 7706baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd. 7716baef150380d561a4d695a6be4fc509821c23611Calin Culianu chanlist_len; 7726baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (n = 0; 7736baef150380d561a4d695a6be4fc509821c23611Calin Culianu n < len; 7746baef150380d561a4d695a6be4fc509821c23611Calin Culianu n++) { 7756baef150380d561a4d695a6be4fc509821c23611Calin Culianu ch = CR_CHAN(s->async->cmd.chanlist[n]); 7766baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (mytrig & (1U << ch)) { 7776baef150380d561a4d695a6be4fc509821c23611Calin Culianu val |= (1U << n); 7786baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7796baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7806baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Write the scan to the buffer. */ 7819b9bcba0cafa2578cebbe0eca01eaafd49f3e43bBill Pemberton if (comedi_buf_put(s->async, ((short *) &val)[0]) 7826baef150380d561a4d695a6be4fc509821c23611Calin Culianu && 7836baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_buf_put 7849b9bcba0cafa2578cebbe0eca01eaafd49f3e43bBill Pemberton (s->async, ((short *) &val)[1])) { 7856baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); 7866baef150380d561a4d695a6be4fc509821c23611Calin Culianu } else { 7876baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Overflow! Stop acquisition!! */ 7886baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 7896baef150380d561a4d695a6be4fc509821c23611Calin Culianu pcmuio_stop_intr 7906baef150380d561a4d695a6be4fc509821c23611Calin Culianu (dev, 7916baef150380d561a4d695a6be4fc509821c23611Calin Culianu s); 7926baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7936baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7946baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Check for end of acquisition. */ 7956baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!subpriv-> 7966baef150380d561a4d695a6be4fc509821c23611Calin Culianu intr. 7976baef150380d561a4d695a6be4fc509821c23611Calin Culianu continuous) 7986baef150380d561a4d695a6be4fc509821c23611Calin Culianu { 7996baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* stop_src == TRIG_COUNT */ 8006baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.stop_count > 0) { 8016baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv-> 8026baef150380d561a4d695a6be4fc509821c23611Calin Culianu intr. 8036baef150380d561a4d695a6be4fc509821c23611Calin Culianu stop_count--; 8046baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.stop_count == 0) { 8056baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events |= COMEDI_CB_EOA; 8066baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 8076baef150380d561a4d695a6be4fc509821c23611Calin Culianu pcmuio_stop_intr 8086baef150380d561a4d695a6be4fc509821c23611Calin Culianu (dev, 8096baef150380d561a4d695a6be4fc509821c23611Calin Culianu s); 8106baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8116baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8126baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8136baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8146baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8156baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8165f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 8176baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8186baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (oldevents != 8196baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events) { 8206baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 8216baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8226baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8236baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8246baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8256baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8266baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8276baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8286baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8296baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8306baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!got1) 8316baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_NONE; /* interrupt from other source */ 8326baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_HANDLED; 8336baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 8346baef150380d561a4d695a6be4fc509821c23611Calin Culianu 835da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void pcmuio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) 8366baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 8376baef150380d561a4d695a6be4fc509821c23611Calin Culianu int nports, firstport, asic, port; 8386baef150380d561a4d695a6be4fc509821c23611Calin Culianu 839c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton asic = subpriv->intr.asic; 840c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton if (asic < 0) 8416baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* not an interrupt subdev */ 8426baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8436baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = 0; 8446baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 8456baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->inttrig = 0; 8466baef150380d561a4d695a6be4fc509821c23611Calin Culianu nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; 8476baef150380d561a4d695a6be4fc509821c23611Calin Culianu firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; 8486baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_ENAB); 8496baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = firstport; port < firstport + nports; ++port) { 8506baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* disable all intrs for this subdev.. */ 8516baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); 8526baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8536baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 8546baef150380d561a4d695a6be4fc509821c23611Calin Culianu 855da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) 8566baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 8576baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { 8586baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* An empty acquisition! */ 8596baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events |= COMEDI_CB_EOA; 8606baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 8616baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 8626baef150380d561a4d695a6be4fc509821c23611Calin Culianu } else { 8636baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned bits = 0, pol_bits = 0, n; 8646baef150380d561a4d695a6be4fc509821c23611Calin Culianu int nports, firstport, asic, port; 865ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 8666baef150380d561a4d695a6be4fc509821c23611Calin Culianu 867c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton asic = subpriv->intr.asic; 868c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton if (asic < 0) 8696baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; /* not an interrupt 8706baef150380d561a4d695a6be4fc509821c23611Calin Culianu subdev */ 8716baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = 0; 8726baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 8736baef150380d561a4d695a6be4fc509821c23611Calin Culianu nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; 8746baef150380d561a4d695a6be4fc509821c23611Calin Culianu firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; 8756baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->chanlist) { 8766baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (n = 0; n < cmd->chanlist_len; n++) { 8776baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits |= (1U << CR_CHAN(cmd->chanlist[n])); 8786baef150380d561a4d695a6be4fc509821c23611Calin Culianu pol_bits |= (CR_AREF(cmd->chanlist[n]) 8796baef150380d561a4d695a6be4fc509821c23611Calin Culianu || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U) 8806baef150380d561a4d695a6be4fc509821c23611Calin Culianu << CR_CHAN(cmd->chanlist[n]); 8816baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8826baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 8836baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits &= ((0x1 << subpriv->intr.num_asic_chans) - 8846baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1) << subpriv->intr.first_chan; 8856baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = bits; 8866baef150380d561a4d695a6be4fc509821c23611Calin Culianu 8876baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_ENAB); 8886baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = firstport; port < firstport + nports; ++port) { 8896baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned enab = 8906baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits >> (subpriv->intr.first_chan + (port - 8916baef150380d561a4d695a6be4fc509821c23611Calin Culianu firstport) * 8) & 0xff, pol = 8926baef150380d561a4d695a6be4fc509821c23611Calin Culianu pol_bits >> (subpriv->intr.first_chan + (port - 8936baef150380d561a4d695a6be4fc509821c23611Calin Culianu firstport) * 8) & 0xff; 8946baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* set enab intrs for this subdev.. */ 8956baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(enab, 8966baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].iobase + REG_ENAB0 + port); 8976baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_POL); 8986baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(pol, 8996baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].iobase + REG_ENAB0 + port); 9006baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9016baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9026baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 9036baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 9046baef150380d561a4d695a6be4fc509821c23611Calin Culianu 905da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 9066baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 9076baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 9086baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9095f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 9106baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.active) 9116baef150380d561a4d695a6be4fc509821c23611Calin Culianu pcmuio_stop_intr(dev, s); 9125f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 9136baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9146baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 9156baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 9166baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9176baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 9186baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. 9196baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 9206baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int 921da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, 9226baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int trignum) 9236baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 9246baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 9256baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 9266baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9276baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (trignum != 0) 9286baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 9296baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9305f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 9316baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->inttrig = 0; 9326baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.active) { 9336baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 9346baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9355f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 9366baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9376baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (event) { 9386baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 9396baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9406baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9416baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 9426baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 9436baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9446baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 9456baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice. 9466baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 947da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 9486baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 949ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 9506baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 9516baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 9526baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9535f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 9546baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 9556baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9566baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up end of acquisition. */ 9576baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->stop_src) { 9586baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_COUNT: 9596baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 0; 9606baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = cmd->stop_arg; 9616baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 9626baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 9636baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NONE */ 9646baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 1; 9656baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = 0; 9666baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 9676baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9686baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9696baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up start of acquisition. */ 9706baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->start_src) { 9716baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_INT: 9726baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->inttrig = pcmuio_inttrig_start_intr; 9736baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 9746baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 9756baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NOW */ 9766baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 9776baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 9786baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9795f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 9806baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9816baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (event) { 9826baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 9836baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 9846baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9856baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 9866baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 9876baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9886baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 9896baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmdtest' function for an 'INTERRUPT' subdevice. 9906baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 9916baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int 992da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) 9936baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 9946baef150380d561a4d695a6be4fc509821c23611Calin Culianu int err = 0; 9956baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int tmp; 9966baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9976baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* step 1: make sure trigger sources are trivially valid */ 9986baef150380d561a4d695a6be4fc509821c23611Calin Culianu 9996baef150380d561a4d695a6be4fc509821c23611Calin Culianu tmp = cmd->start_src; 10006baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->start_src &= (TRIG_NOW | TRIG_INT); 10016baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!cmd->start_src || tmp != cmd->start_src) 10026baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10036baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10046baef150380d561a4d695a6be4fc509821c23611Calin Culianu tmp = cmd->scan_begin_src; 10056baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->scan_begin_src &= TRIG_EXT; 10066baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 10076baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10086baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10096baef150380d561a4d695a6be4fc509821c23611Calin Culianu tmp = cmd->convert_src; 10106baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->convert_src &= TRIG_NOW; 10116baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!cmd->convert_src || tmp != cmd->convert_src) 10126baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10136baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10146baef150380d561a4d695a6be4fc509821c23611Calin Culianu tmp = cmd->scan_end_src; 10156baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->scan_end_src &= TRIG_COUNT; 10166baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 10176baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10186baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10196baef150380d561a4d695a6be4fc509821c23611Calin Culianu tmp = cmd->stop_src; 10206baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); 10216baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!cmd->stop_src || tmp != cmd->stop_src) 10226baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10236baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10246baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (err) 10256baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 10266baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10276baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* step 2: make sure trigger sources are unique and mutually compatible */ 10286baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10296baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* these tests are true if more than one _src bit is set */ 10306baef150380d561a4d695a6be4fc509821c23611Calin Culianu if ((cmd->start_src & (cmd->start_src - 1)) != 0) 10316baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10326baef150380d561a4d695a6be4fc509821c23611Calin Culianu if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) 10336baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10346baef150380d561a4d695a6be4fc509821c23611Calin Culianu if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) 10356baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10366baef150380d561a4d695a6be4fc509821c23611Calin Culianu if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) 10376baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10386baef150380d561a4d695a6be4fc509821c23611Calin Culianu if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) 10396baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10406baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10416baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (err) 10426baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 2; 10436baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10446baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* step 3: make sure arguments are trivially compatible */ 10456baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10466baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ 10476baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->start_arg != 0) { 10486baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->start_arg = 0; 10496baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10506baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10516baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10526baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* cmd->scan_begin_src == TRIG_EXT */ 10536baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->scan_begin_arg != 0) { 10546baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->scan_begin_arg = 0; 10556baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10566baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10576baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10586baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* cmd->convert_src == TRIG_NOW */ 10596baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->convert_arg != 0) { 10606baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->convert_arg = 0; 10616baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10626baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10636baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10646baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* cmd->scan_end_src == TRIG_COUNT */ 10656baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->scan_end_arg != cmd->chanlist_len) { 10666baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->scan_end_arg = cmd->chanlist_len; 10676baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10686baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10696baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10706baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->stop_src) { 10716baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_COUNT: 10726baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* any count allowed */ 10736baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 10746baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_NONE: 10756baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->stop_arg != 0) { 10766baef150380d561a4d695a6be4fc509821c23611Calin Culianu cmd->stop_arg = 0; 10776baef150380d561a4d695a6be4fc509821c23611Calin Culianu err++; 10786baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10796baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 10806baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 10816baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 10826baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 10836baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10846baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (err) 10856baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 3; 10866baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10876baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* step 4: fix up any arguments */ 10886baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10896baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* if (err) return 4; */ 10906baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10916baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 10926baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 10936baef150380d561a4d695a6be4fc509821c23611Calin Culianu 10946baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 10956baef150380d561a4d695a6be4fc509821c23611Calin Culianu * A convenient macro that defines init_module() and cleanup_module(), 10966baef150380d561a4d695a6be4fc509821c23611Calin Culianu * as necessary. 10976baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 10986baef150380d561a4d695a6be4fc509821c23611Calin CulianuCOMEDI_INITCLEANUP(driver); 1099