pcmuio.c revision 9e1087b5ae4c31c812e3f8a35256d7922a1cdbd6
16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 29e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * pcmuio.c 39e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Comedi driver for Winsystems PC-104 based 48/96-channel DIO boards. 49e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 59e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * COMEDI - Linux Control and Measurement Device Interface 69e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> 79e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 89e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is free software; you can redistribute it and/or modify 99e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * it under the terms of the GNU General Public License as published by 109e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the Free Software Foundation; either version 2 of the License, or 119e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (at your option) any later version. 129e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 139e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is distributed in the hope that it will be useful, 149e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * but WITHOUT ANY WARRANTY; without even the implied warranty of 159e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 169e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * GNU General Public License for more details. 179e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */ 186baef150380d561a4d695a6be4fc509821c23611Calin Culianu 196baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 209e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Driver: pcmuio 219e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Description: Winsystems PC-104 based 48/96-channel DIO boards. 229e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Devices: (Winsystems) PCM-UIO48A [pcmuio48] 239e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (Winsystems) PCM-UIO96A [pcmuio96] 249e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Author: Calin Culianu <calin@ajvar.org> 259e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Updated: Fri, 13 Jan 2006 12:01:01 -0500 269e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Status: works 279e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 289e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * A driver for the relatively straightforward-to-program PCM-UIO48A and 299e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * PCM-UIO96A boards from Winsystems. These boards use either one or two 309e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). This 319e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chip is interesting in that each I/O line is individually programmable 329e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for INPUT or OUTPUT (thus comedi_dio_config can be done on a per-channel 339e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * basis). Also, each chip supports edge-triggered interrupts for the first 349e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 24 I/O lines. Of course, since the 96-channel version of the board has 359e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * two ASICs, it can detect polarity changes on up to 48 I/O lines. Since 369e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * this is essentially an (non-PnP) ISA board, I/O Address and IRQ selection 379e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * are done through jumpers on the board. You need to pass that information 389e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * to this driver as the first and second comedi_config option, respectively. 399e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that the 48-channel version uses 16 bytes of IO memory and the 96- 409e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * channel version uses 32-bytes (in case you are worried about conflicts). 419e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * The 48-channel board is split into two 24-channel comedi subdevices. The 429e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96-channel board is split into 4 24-channel DIO subdevices. 439e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 449e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that IRQ support has been added, but it is untested. 459e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 469e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To use edge-detection IRQ support, pass the IRQs of both ASICS (for the 479e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96 channel version) or just 1 ASIC (for 48-channel version). Then, use 489e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * comedi_commands with TRIG_NOW. Your callback will be called each time an 499e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * edge is triggered, and the data values will be two sample_t's, which 509e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * should be concatenated to form one 32-bit unsigned int. This value is 519e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the mask of channels that had edges detected from your channel list. Note 529e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * that the bits positions in the mask correspond to positions in your 539e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chanlist when you specified the command and *not* channel id's! 549e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 559e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To set the polarity of the edge-detection interrupts pass a nonzero value 569e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for 579e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * both CR_RANGE and CR_AREF if you want edge-down polarity. 589e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 599e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 48-channel version: 609e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 619e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * On subdev 0, the first 24 channels channels are edge-detect channels. 629e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 639e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 96-channel board you have the following channels that can do edge 649e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * detection: 659e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 669e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 0, channels 0-24 (first 24 channels of 1st ASIC) 679e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) 689e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 699e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Configuration Options: 709e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [0] - I/O port base address 719e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [1] - IRQ (for first ASIC, or first 24 channels) 729e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * [2] - IRQ (for second ASIC, pcmuio96 only - IRQ for chans 48-72 739e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * can be the same as first irq!) 749e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */ 756baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7625436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h> 775a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 786baef150380d561a4d695a6be4fc509821c23611Calin Culianu 79f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "../comedidev.h" 8033782dd5edf8db3cdb7c81a3523bf743dd0209b7H Hartley Sweeten 81f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "comedi_fc.h" 826baef150380d561a4d695a6be4fc509821c23611Calin Culianu 836baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT 8 846baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC 6 856baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC 3 866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ 876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) 886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) 896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24 906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) 916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT) 926baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) 936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) 946baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */ 956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x10) 966baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO48_IOSIZE ASIC_IOSIZE 976baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2) 986baef150380d561a4d695a6be4fc509821c23611Calin Culianu 996baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from 1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu the base address. Note that there is a paging scheme to swap out 1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu offsets 0x8-0xA using the PAGELOCK register. See the table below. 1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu Register(s) Pages R/W? Description 1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu -------------------------------------------------------------- 1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_PORTx All R/W Read/Write/Configure IO 1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. 1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_PAGELOCK All WriteOnly Select a page 1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity 1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. 1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. 1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0 1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1 1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2 1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3 1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4 1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5 1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6 1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page 1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu and bits 0-5 are used to 'lock down' a particular 1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu port above to make it readonly. */ 1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8 1236baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9 1246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA 1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8 1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9 1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA 1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8 1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9 1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA 1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3 1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4 1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8 1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6 1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0 1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) 1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_MASK ~(REG_PAGE_MASK) 1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1 1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2 1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3 1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards. Describing the 1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent. 1466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not. 1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 14870a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board { 1496baef150380d561a4d695a6be4fc509821c23611Calin Culianu const char *name; 1506baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_asics; 1516baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_channels_per_port; 1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu const int num_ports; 15370a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton}; 1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice. */ 156e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private { 1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* mapping of halfwords (bytes) in port/chanarray to iobase */ 1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobases[PORTS_PER_SUBDEV]; 1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1606baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The below is only used for intr subdevices */ 1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic; /* if non-negative, this subdev has an interrupt asic */ 1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu int first_chan; /* if nonnegative, the first channel id for 1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu interrupts. */ 1656baef150380d561a4d695a6be4fc509821c23611Calin Culianu int num_asic_chans; /* the number of asic channels in this subdev 1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu that have interrutps */ 1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic_chan; /* if nonnegative, the first channel id with 1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu respect to the asic that has interrupts */ 1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu int enabled_mask; /* subdev-relative channel mask for channels 1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu we are interested in */ 1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu int active; 1726baef150380d561a4d695a6be4fc509821c23611Calin Culianu int stop_count; 1736baef150380d561a4d695a6be4fc509821c23611Calin Culianu int continuous; 1746baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 1756baef150380d561a4d695a6be4fc509821c23611Calin Culianu } intr; 176e15849e54405152087cd343437747db8d931fcd7Bill Pemberton}; 1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1786baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver. If 1796baef150380d561a4d695a6be4fc509821c23611Calin Culianu several hardware drivers keep similar information in this structure, 18071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton feel free to suggest moving the variable to the struct comedi_device struct. */ 181055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private { 1826baef150380d561a4d695a6be4fc509821c23611Calin Culianu struct { 1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char pagelock; /* current page and lock */ 1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */ 1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */ 1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu int num; 1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long iobase; 1886baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned int irq; 1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu spinlock_t spinlock; 1906baef150380d561a4d695a6be4fc509821c23611Calin Culianu } asics[MAX_ASICS]; 191e15849e54405152087cd343437747db8d931fcd7Bill Pemberton struct pcmuio_subdev_private *sprivs; 192055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton}; 1936baef150380d561a4d695a6be4fc509821c23611Calin Culianu 1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special. Although it is possible to 1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more 1966baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface. 1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels. The 1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */ 1990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev, 2000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s, 2010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_insn *insn, unsigned int *data) 2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 2038099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 2046baef150380d561a4d695a6be4fc509821c23611Calin Culianu int byte_no; 2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 0 means this channel was high 2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu writine a 0 sets the channel high 2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu reading a 1 means this channel was low 2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 means set this channel low 2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu Therefore everything is always inverted. */ 2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* The insn data is a mask in data[0] and the new data 2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in data[1], each channel cooresponding to a bit. */ 2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 219f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "write mask: %08x data: %08x\n", data[0], 220976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya data[1]); 2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state = 0; 2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { 2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* address of 8-bit port */ 2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long ioaddr = subpriv->iobases[byte_no], 2280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* bit offset of port in 32-bit doubleword */ 2290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral offset = byte_no * 8; 2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this 8-bit port's data */ 2316baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte = 0, 2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* The write mask for this port (if any) */ 2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral write_mask_byte = (data[0] >> offset) & 0xff, 2340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* The data byte for this port */ 2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral data_byte = (data[1] >> offset) & 0xff; 2366baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte = inb(ioaddr); /* read all 8-bits for this port */ 2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 2406baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk 2420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", 2430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, 2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral offset, ioaddr, (unsigned)byte); 2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (write_mask_byte) { 2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* this byte has some write_bits -- so set the output lines */ 2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte &= ~write_mask_byte; /* clear bits for write mask */ 2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */ 2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Write out the new digital output state */ 2526baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(byte, ioaddr); 2536baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 2546baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 256f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte); 2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save the digital input lines for this byte.. */ 2596baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->state |= ((unsigned int)byte) << offset; 2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now return the DIO lines to data[1] - note they came inverted! */ 2636baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = ~s->state; 2646baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN 2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG */ 267f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state, 268976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya data[1]); 2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif 2706baef150380d561a4d695a6be4fc509821c23611Calin Culianu 271a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten return insn->n; 2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 2736baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2746baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is 2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction. chanspec 2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the 2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */ 2780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev, 2790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s, 2800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_insn *insn, unsigned int *data) 2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 2828099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = 2840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral chan % 8; 2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long ioaddr; 2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned char byte; 2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Compute ioaddr for this channel */ 2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu ioaddr = subpriv->iobases[byte_no]; 2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* NOTE: 2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 0 an IO channel's bit sets the channel to INPUT 2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu and pulls the line high as well 2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu writing a 1 to an IO channel's bit pulls the line low 2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu 2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu All channels are implicitly always in OUTPUT mode -- but when 2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu they are high they can be considered to be in INPUT mode.. 2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu Thus, we only force channels low if the config request was INPUT, 3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu otherwise we do nothing to the hardware. */ 3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (data[0]) { 3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_OUTPUT: 3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits -- don't actually do anything since 3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu all input channels are also output channels... */ 3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits |= 1 << chan; 3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_INPUT: 3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* write a 0 to the actual register representing the channel 3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu to set it to 'input'. 0 means "float high". */ 3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte = inb(ioaddr); 3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu byte &= ~(1 << bit_no); 3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu /**< set input channel to '0' */ 3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* write out byte -- this is the only time we actually affect the 3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu hardware as all channels are implicitly output -- but input 3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu channels are set to float-high */ 3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(byte, ioaddr); 3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* save to io_bits */ 3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->io_bits &= ~(1 << chan); 3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu case INSN_CONFIG_DIO_QUERY: 32625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* retrieve from shadow register */ 3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu data[1] = 3280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 3306baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu return insn->n; 3386baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 3396baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void switch_page(struct comedi_device *dev, int asic, int page) 3416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 342a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 3439a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 344a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten 345a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten if (asic < 0 || asic >= board->num_asics) 3466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return; /* paranoia */ 3476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (page < 0 || page >= NUM_PAGES) 3486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return; /* more paranoia */ 3496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 3506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; 3516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; 3526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 3536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* now write out the shadow register */ 3546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten outb(devpriv->asics[asic].pagelock, 3556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 3566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 3576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 358da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev) 3596baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ /* sets up an 3606baef150380d561a4d695a6be4fc509821c23611Calin Culianu ASIC chip to defaults */ 361a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 3626baef150380d561a4d695a6be4fc509821c23611Calin Culianu int asic; 3636baef150380d561a4d695a6be4fc509821c23611Calin Culianu 364a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten for (asic = 0; asic < board->num_asics; ++asic) { 3656baef150380d561a4d695a6be4fc509821c23611Calin Culianu int port, page; 3666baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE; 3676baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, 0); /* switch back to page 0 */ 3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* first, clear all the DIO port bits */ 3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = 0; port < PORTS_PER_ASIC; ++port) 3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, baseaddr + REG_PORT0 + port); 3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Next, clear all the paged registers for each page */ 3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (page = 1; page < NUM_PAGES; ++page) { 3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu int reg; 3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now clear all the paged registers */ 3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, page); 3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (reg = FIRST_PAGED_REG; 3800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) 3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0, baseaddr + reg); 3826baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* DEBUG set rising edge interrupts on port0 of both asics */ 3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu /*switch_page(dev, asic, PAGE_POL); 3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0xff, baseaddr + REG_POL0); 3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_ENAB); 3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(0xff, baseaddr + REG_ENAB0); */ 3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* END DEBUG */ 3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, 0); /* switch back to default page 0 */ 3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu 3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused 397da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port) 3986baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 399a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 4009a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 401a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten 402a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten if (asic < 0 || asic >= board->num_asics) 4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* paranoia */ 4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (port < 0 || port >= PORTS_PER_ASIC) 4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* more paranoia */ 4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock |= 0x1 << port; 4086baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now write out the shadow register */ 4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(devpriv->asics[asic].pagelock, 4100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 4116baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 4126baef150380d561a4d695a6be4fc509821c23611Calin Culianu 413da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port) 4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 415a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 4169a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 417a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten 418a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten if (asic < 0 || asic >= board->num_asics) 4196baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* paranoia */ 4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (port < 0 || port >= PORTS_PER_ASIC) 4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu return; /* more paranoia */ 4226baef150380d561a4d695a6be4fc509821c23611Calin Culianu devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; 4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* now write out the shadow register */ 4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(devpriv->asics[asic].pagelock, 4250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); 4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 4276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */ 4286baef150380d561a4d695a6be4fc509821c23611Calin Culianu 4296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev, 4306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten struct comedi_subdevice *s) 4316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 4329a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 4338099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 4348099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten int nports, firstport, asic, port; 4356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 4366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten asic = subpriv->intr.asic; 4376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (asic < 0) 4386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return; /* not an interrupt subdev */ 4396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 4406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.enabled_mask = 0; 4416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.active = 0; 442920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten s->async->inttrig = NULL; 4436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; 4446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; 4456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten switch_page(dev, asic, PAGE_ENAB); 4466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (port = firstport; port < firstport + nports; ++port) { 4476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* disable all intrs for this subdev.. */ 4486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); 4496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 4506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 4516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 4523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic void pcmuio_handle_intr_subdev(struct comedi_device *dev, 4533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_subdevice *s, 4543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned triggered) 4553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{ 4563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 4573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int len = s->async->cmd.chanlist_len; 4583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned oldevents = s->async->events; 4593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int val = 0; 4603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned long flags; 4613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned mytrig; 4623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int i; 4633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_lock_irqsave(&subpriv->intr.spinlock, flags); 4653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!subpriv->intr.active) 4673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten goto done; 4683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten mytrig = triggered >> subpriv->intr.asic_chan; 4703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten mytrig &= ((0x1 << subpriv->intr.num_asic_chans) - 1); 4713b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten mytrig <<= subpriv->intr.first_chan; 4723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!(mytrig & subpriv->intr.enabled_mask)) 4743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten goto done; 4753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < len; i++) { 4773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]); 4783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (mytrig & (1U << chan)) 4793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten val |= (1U << i); 4803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Write the scan to the buffer. */ 4833b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (comedi_buf_put(s->async, ((short *)&val)[0]) && 4843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten comedi_buf_put(s->async, ((short *)&val)[1])) { 4853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); 4863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } else { 4873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Overflow! Stop acquisition!! */ 4883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 4893b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_stop_intr(dev, s); 4903b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 4913b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 4923b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* Check for end of acquisition. */ 4933b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (!subpriv->intr.continuous) { 4943b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* stop_src == TRIG_COUNT */ 4953b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.stop_count > 0) { 4963b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten subpriv->intr.stop_count--; 4973b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.stop_count == 0) { 4983b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s->async->events |= COMEDI_CB_EOA; 4993b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 5003b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_stop_intr(dev, s); 5013b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5023b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5033b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5043b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5053b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetendone: 5063b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 5073b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5083b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (oldevents != s->async->events) 5093b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten comedi_event(dev, s); 5103b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten} 5113b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5123b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) 5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5149a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 5158099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv; 5163b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned long iobase = devpriv->asics[asic].iobase; 5173b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned triggered = 0; 5183b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int got1 = 0; 5193b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned long flags; 5203b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned char int_pend; 52168720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten int i; 5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5233b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); 5243b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5253b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int_pend = inb(iobase + REG_INT_PENDING) & 0x07; 5263b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (int_pend) { 5273b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < INTR_PORTS_PER_ASIC; ++i) { 5283b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (int_pend & (0x1 << i)) { 5293b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten unsigned char val; 5303b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5313b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten switch_page(dev, asic, PAGE_INT_ID); 5323b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten val = inb(iobase + REG_INT_ID0 + i); 5333b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (val) 5343b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* clear pending interrupt */ 5353b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten outb(0, iobase + REG_INT_ID0 + i); 5363b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5373b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten triggered |= (val << (i * 8)); 5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5393b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5406baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten ++got1; 5423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); 5453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5463b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (triggered) { 5473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_subdevice *s; 5483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* TODO here: dispatch io lines to subdevs with commands.. */ 5493b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (i = 0; i < dev->n_subdevices; i++) { 5503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten s = &dev->subdevices[i]; 5513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten subpriv = s->private; 5523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (subpriv->intr.asic == asic) { 5533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* 5543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten * This is an interrupt subdev, and it 5553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten * matches this asic! 5563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten */ 5573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten pcmuio_handle_intr_subdev(dev, s, 5583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten triggered); 5596baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten } 5623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten return got1; 5633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten} 5643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten 5653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic irqreturn_t interrupt_pcmuio(int irq, void *d) 5663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{ 5673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct comedi_device *dev = d; 5683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 5693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int got1 = 0; 5703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten int asic; 5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten for (asic = 0; asic < MAX_ASICS; ++asic) { 5733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (irq == devpriv->asics[asic].irq) { 5743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten /* it is an interrupt for ASIC #asic */ 5753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten if (pcmuio_handle_asic_interrupt(dev, asic)) 5763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten got1++; 5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!got1) 5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_NONE; /* interrupt from other source */ 5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu return IRQ_HANDLED; 5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu 5840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev, 5850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s) 5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 5879a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 5888099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 5899a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten 5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { 5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* An empty acquisition! */ 5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->events |= COMEDI_CB_EOA; 5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 0; 5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu } else { 5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned bits = 0, pol_bits = 0, n; 5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu int nports, firstport, asic, port; 598ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 5996baef150380d561a4d695a6be4fc509821c23611Calin Culianu 600c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton asic = subpriv->intr.asic; 601c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton if (asic < 0) 6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; /* not an interrupt 6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu subdev */ 6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = 0; 6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; 6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; 6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (cmd->chanlist) { 6096baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (n = 0; n < cmd->chanlist_len; n++) { 6106baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits |= (1U << CR_CHAN(cmd->chanlist[n])); 6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu pol_bits |= (CR_AREF(cmd->chanlist[n]) 6120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral || CR_RANGE(cmd-> 6130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral chanlist[n]) ? 1U : 0U) 6140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral << CR_CHAN(cmd->chanlist[n]); 6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu bits &= ((0x1 << subpriv->intr.num_asic_chans) - 6180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral 1) << subpriv->intr.first_chan; 6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.enabled_mask = bits; 6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_ENAB); 6226baef150380d561a4d695a6be4fc509821c23611Calin Culianu for (port = firstport; port < firstport + nports; ++port) { 6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned enab = 6240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bits >> (subpriv->intr.first_chan + (port - 6250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral firstport) * 6260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral 8) & 0xff, pol = 6270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral pol_bits >> (subpriv->intr.first_chan + 6280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (port - firstport) * 8) & 0xff; 6296baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* set enab intrs for this subdev.. */ 6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(enab, 6310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral devpriv->asics[asic].iobase + REG_ENAB0 + port); 6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch_page(dev, asic, PAGE_POL); 6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu outb(pol, 6340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral devpriv->asics[asic].iobase + REG_ENAB0 + port); 6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 6376baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 6386baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6396baef150380d561a4d695a6be4fc509821c23611Calin Culianu 640da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6428099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 6436baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6455f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 6466baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (subpriv->intr.active) 6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu pcmuio_stop_intr(dev, s); 6485f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6506baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6526baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 6546baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. 6556baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 6566baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int 657da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, 6580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int trignum) 6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6608099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 6616baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu if (trignum != 0) 6656baef150380d561a4d695a6be4fc509821c23611Calin Culianu return -EINVAL; 6666baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6675f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 668920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten s->async->inttrig = NULL; 6690389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (subpriv->intr.active) 6706baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 6710389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya 6725f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6740389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (event) 6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 1; 6786baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 6796baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* 6816baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice. 6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu */ 683da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 6846baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 6858099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv = s->private; 686ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd *cmd = &s->async->cmd; 6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu unsigned long flags; 6886baef150380d561a4d695a6be4fc509821c23611Calin Culianu int event = 0; 6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6905f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&subpriv->intr.spinlock, flags); 6916baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.active = 1; 6926baef150380d561a4d695a6be4fc509821c23611Calin Culianu 6936baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up end of acquisition. */ 6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->stop_src) { 6956baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_COUNT: 6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 0; 6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = cmd->stop_arg; 6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NONE */ 7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.continuous = 1; 7026baef150380d561a4d695a6be4fc509821c23611Calin Culianu subpriv->intr.stop_count = 0; 7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* Set up start of acquisition. */ 7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu switch (cmd->start_src) { 7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu case TRIG_INT: 7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu s->async->inttrig = pcmuio_inttrig_start_intr; 7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu default: 7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu /* TRIG_NOW */ 7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu event = pcmuio_start_intr(dev, s); 7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu break; 7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu } 7165f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); 7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7180389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya if (event) 7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu comedi_event(dev, s); 7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu return 0; 7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu 724f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev, 725f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten struct comedi_subdevice *s, 726f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten struct comedi_cmd *cmd) 7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu{ 728f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten int err = 0; 729f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 730f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 1 : check if triggers are trivially valid */ 731f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 732f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); 733f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); 734f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); 735f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 736f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 737f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 738f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 739f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 1; 740f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 741f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 2a : make sure trigger sources are unique */ 742f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 743f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_is_unique(cmd->start_src); 744f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_is_unique(cmd->stop_src); 745f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 746f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 2b : and mutually compatible */ 747f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 748f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 749f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 2; 750f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 751f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* Step 3: check if arguments are trivially valid */ 752f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 753f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 754f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 755f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 756f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 757f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 758f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten switch (cmd->stop_src) { 759f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten case TRIG_COUNT: 760f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* any count allowed */ 761f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 762f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten case TRIG_NONE: 763f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 764f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 765f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten default: 766f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten break; 767f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten } 768f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 769f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten if (err) 770f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 3; 771f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 772f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* step 4: fix up any arguments */ 773f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 774f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten /* if (err) return 4; */ 775f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten 776f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten return 0; 7776baef150380d561a4d695a6be4fc509821c23611Calin Culianu} 7786baef150380d561a4d695a6be4fc509821c23611Calin Culianu 7796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) 7806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 781a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten const struct pcmuio_board *board = comedi_board(dev); 7826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten struct comedi_subdevice *s; 7838099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_private *devpriv; 7848099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten struct pcmuio_subdev_private *subpriv; 7856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; 7866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten unsigned int irq[MAX_ASICS]; 7878b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten int ret; 7886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 7896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[0] = it->options[1]; 7906b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[1] = it->options[2]; 7916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 79235626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten ret = comedi_request_region(dev, it->options[0], 79335626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten board->num_asics * ASIC_IOSIZE); 79435626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten if (ret) 79535626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten return ret; 7966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 797c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); 798c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten if (!devpriv) 799c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten return -ENOMEM; 800c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten dev->private = devpriv; 8016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (asic = 0; asic < MAX_ASICS; ++asic) { 8036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].num = asic; 8046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; 8056b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].irq = 0; /* this gets actually set at the end of 8066b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten this function when we 8076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten request_irqs */ 8086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten spin_lock_init(&devpriv->asics[asic].spinlock); 8096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 811a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten chans_left = CHANS_PER_ASIC * board->num_asics; 8126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten n_subdevs = CALC_N_SUBDEVS(chans_left); 81378110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches devpriv->sprivs = kcalloc(n_subdevs, 81478110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches sizeof(struct pcmuio_subdev_private), 81578110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches GFP_KERNEL); 81678110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches if (!devpriv->sprivs) 8176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return -ENOMEM; 818eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten 8198b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten ret = comedi_alloc_subdevices(dev, n_subdevs); 8208b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten if (ret) 8218b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten return ret; 8226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten port = 0; 8246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten asic = 0; 8256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { 8266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int byte_no; 8276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 82868720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten s = &dev->subdevices[sdev_no]; 8298099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten subpriv = &devpriv->sprivs[sdev_no]; 8308099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten s->private = subpriv; 8316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->maxdata = 1; 8326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->range_table = &range_digital; 8336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 8346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->type = COMEDI_SUBD_DIO; 8356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->insn_bits = pcmuio_dio_insn_bits; 8366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->insn_config = pcmuio_dio_insn_config; 8376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); 8386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.asic = -1; 8396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.first_chan = -1; 8406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.asic_chan = -1; 8416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.num_asic_chans = -1; 8426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.active = 0; 8436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->len_chanlist = 1; 8446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* save the ioport address for each 'port' of 8 channels in the 8466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subdevice */ 8476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { 8486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (port >= PORTS_PER_ASIC) { 8496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten port = 0; 8506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten ++asic; 8516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten thisasic_chanct = 0; 8526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->iobases[byte_no] = 8546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].iobase + port; 8556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (thisasic_chanct < 8576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten CHANS_PER_PORT * INTR_PORTS_PER_ASIC 8586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten && subpriv->intr.asic < 0) { 8596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* this is an interrupt subdevice, so setup the struct */ 8606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.asic = asic; 8616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.active = 0; 8626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.stop_count = 0; 8636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.first_chan = byte_no * 8; 8646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.asic_chan = thisasic_chanct; 8656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten subpriv->intr.num_asic_chans = 8666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->n_chan - subpriv->intr.first_chan; 8676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten dev->read_subdev = s; 8686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->subdev_flags |= SDF_CMD_READ; 8696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->cancel = pcmuio_cancel; 8706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->do_cmd = pcmuio_cmd; 8716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->do_cmdtest = pcmuio_cmdtest; 8726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten s->len_chanlist = subpriv->intr.num_asic_chans; 8736b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten thisasic_chanct += CHANS_PER_PORT; 8756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8766b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten spin_lock_init(&subpriv->intr.spinlock); 8776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten chans_left -= s->n_chan; 8796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (!chans_left) { 8816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten asic = 0; /* reset the asic to our first asic, to do intr subdevs */ 8826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten port = 0; 8836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten init_asics(dev); /* clear out all the registers, basically */ 8886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 8896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { 8906b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (irq[asic] 8916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten && request_irq(irq[asic], interrupt_pcmuio, 892a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten IRQF_SHARED, board->name, dev)) { 8936b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int i; 8946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten /* unroll the allocated irqs.. */ 8956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (i = asic - 1; i >= 0; --i) { 8966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten free_irq(irq[i], dev); 8976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[i].irq = irq[i] = 0; 8986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 8996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten irq[asic] = 0; 9006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 9016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten devpriv->asics[asic].irq = irq[asic]; 9026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 9036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 9046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (irq[0]) { 905f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "irq: %u\n", irq[0]); 906a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten if (irq[1] && board->num_asics == 2) 907f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "second ASIC irq: %u\n", 908f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott irq[1]); 9096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } else { 910f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott dev_dbg(dev->class_dev, "(IRQ mode disabled)\n"); 9116b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 9126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 9136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 9146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten return 1; 9156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 9166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 917484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev) 9186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{ 9199a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten struct pcmuio_private *devpriv = dev->private; 9206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten int i; 9216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 9226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten for (i = 0; i < MAX_ASICS; ++i) { 9236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (devpriv->asics[i].irq) 9246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten free_irq(devpriv->asics[i].irq, dev); 9256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten } 9266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten if (devpriv && devpriv->sprivs) 9276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten kfree(devpriv->sprivs); 928a32c6d0084992d3e58a93120c9ce9527e80c651eH Hartley Sweeten comedi_legacy_detach(dev); 9296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten} 9306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 9316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = { 9326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten { 9336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .name = "pcmuio48", 9346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_asics = 1, 9356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_ports = 6, 9366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten }, { 9376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .name = "pcmuio96", 9386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_asics = 2, 9396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_ports = 12, 9406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten }, 9416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}; 9426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten 943294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = { 9446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .driver_name = "pcmuio", 9456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .module = THIS_MODULE, 9466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .attach = pcmuio_attach, 9476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .detach = pcmuio_detach, 9486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .board_name = &pcmuio_boards[0].name, 9496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .offset = sizeof(struct pcmuio_board), 9506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten .num_names = ARRAY_SIZE(pcmuio_boards), 9516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}; 952294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver); 95390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas 95490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org"); 95590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver"); 95690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL"); 957