linux/drivers/staging/meilhaus/me1400_ext_irq.c
<<
>>
Prefs
   1/**
   2 * @file me1400_ext_irq.c
   3 *
   4 * @brief ME-1400 external interrupt subdevice instance.
   5 * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
   6 * @author Guenter Gebhardt
   7 * @author Krzysztof Gantzke    (k.gantzke@meilhaus.de)
   8 */
   9
  10/*
  11 * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
  12 *
  13 * This file is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#ifndef __KERNEL__
  29#  define __KERNEL__
  30#endif
  31
  32/*
  33 * Includes
  34 */
  35#include <linux/version.h>
  36#include <linux/module.h>
  37
  38#include <linux/slab.h>
  39#include <linux/spinlock.h>
  40#include <asm/io.h>
  41#include <linux/types.h>
  42#include <linux/interrupt.h>
  43
  44#include "medefines.h"
  45#include "meinternal.h"
  46#include "meerror.h"
  47#include "medebug.h"
  48#include "meids.h"
  49
  50#include "me1400_ext_irq.h"
  51#include "me1400_ext_irq_reg.h"
  52
  53/*
  54 * Defines
  55 */
  56#define ME1400_EXT_IRQ_MAGIC_NUMBER     0x1401  /**< The magic number of the class structure. */
  57#define ME1400_EXT_IRQ_NUMBER_CHANNELS 1        /**< One channel per counter. */
  58
  59/*
  60 * Functions
  61 */
  62
  63static int me1400_ext_irq_io_irq_start(struct me_subdevice *subdevice,
  64                                       struct file *filep,
  65                                       int channel,
  66                                       int irq_source,
  67                                       int irq_edge, int irq_arg, int flags)
  68{
  69        me1400_ext_irq_subdevice_t *instance;
  70        unsigned long cpu_flags;
  71        uint8_t tmp;
  72
  73        PDEBUG("executed.\n");
  74
  75        instance = (me1400_ext_irq_subdevice_t *) subdevice;
  76
  77        if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
  78                PERROR("Invalid flag specified.\n");
  79                return ME_ERRNO_INVALID_FLAGS;
  80        }
  81
  82        if (channel) {
  83                PERROR("Invalid channel.\n");
  84                return ME_ERRNO_INVALID_CHANNEL;
  85        }
  86
  87        if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
  88                PERROR("Invalid irq source.\n");
  89                return ME_ERRNO_INVALID_IRQ_SOURCE;
  90        }
  91
  92        if (irq_edge != ME_IRQ_EDGE_RISING) {
  93                PERROR("Invalid irq edge.\n");
  94                return ME_ERRNO_INVALID_IRQ_EDGE;
  95        }
  96
  97        ME_SUBDEVICE_ENTER;
  98
  99        spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
 100
 101        spin_lock(instance->clk_src_reg_lock);
 102//                      // Enable IRQ on PLX
 103//                      tmp = inb(instance->plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN);
 104//                      outb(tmp, instance->plx_intcs_reg);
 105//                      PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
 106
 107        // Enable IRQ
 108        switch (instance->device_id) {
 109        case PCI_DEVICE_ID_MEILHAUS_ME140C:
 110        case PCI_DEVICE_ID_MEILHAUS_ME140D:
 111                tmp = inb(instance->ctrl_reg);
 112                tmp |= ME1400CD_EXT_IRQ_CLK_EN;
 113                outb(tmp, instance->ctrl_reg);
 114                PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
 115                           instance->reg_base,
 116                           instance->ctrl_reg - instance->reg_base, tmp);
 117                break;
 118
 119        default:
 120                outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
 121                PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
 122                           instance->reg_base,
 123                           instance->ctrl_reg - instance->reg_base,
 124                           ME1400AB_EXT_IRQ_IRQ_EN);
 125                break;
 126        }
 127        spin_unlock(instance->clk_src_reg_lock);
 128        instance->rised = 0;
 129        spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
 130
 131        ME_SUBDEVICE_EXIT;
 132
 133        return ME_ERRNO_SUCCESS;
 134}
 135
 136static int me1400_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
 137                                      struct file *filep,
 138                                      int channel,
 139                                      int *irq_count,
 140                                      int *value, int time_out, int flags)
 141{
 142        me1400_ext_irq_subdevice_t *instance;
 143        unsigned long cpu_flags;
 144        long t = 0;
 145        int err = ME_ERRNO_SUCCESS;
 146
 147        PDEBUG("executed.\n");
 148
 149        instance = (me1400_ext_irq_subdevice_t *) subdevice;
 150
 151        if (flags) {
 152                PERROR("Invalid flag specified.\n");
 153                return ME_ERRNO_INVALID_FLAGS;
 154        }
 155
 156        if (channel) {
 157                PERROR("Invalid channel.\n");
 158                return ME_ERRNO_INVALID_CHANNEL;
 159        }
 160
 161        if (time_out < 0) {
 162                PERROR("Invalid time out.\n");
 163                return ME_ERRNO_INVALID_TIMEOUT;
 164        }
 165
 166        if (time_out) {
 167                /* Convert to ticks */
 168                t = (time_out * HZ) / 1000;
 169
 170                if (t == 0)
 171                        t = 1;
 172        }
 173
 174        ME_SUBDEVICE_ENTER;
 175
 176        if (instance->rised <= 0) {
 177                instance->rised = 0;
 178                if (time_out) {
 179                        t = wait_event_interruptible_timeout(instance->
 180                                                             wait_queue,
 181                                                             (instance->rised !=
 182                                                              0), t);
 183
 184                        if (t == 0) {
 185                                PERROR("Wait on interrupt timed out.\n");
 186                                err = ME_ERRNO_TIMEOUT;
 187                        }
 188                } else {
 189                        wait_event_interruptible(instance->wait_queue,
 190                                                 (instance->rised != 0));
 191                }
 192
 193                if (instance->rised < 0) {
 194                        PERROR("Wait on interrupt aborted by user.\n");
 195                        err = ME_ERRNO_CANCELLED;
 196                }
 197        }
 198
 199        if (signal_pending(current)) {
 200                PERROR("Wait on interrupt aborted by signal.\n");
 201                err = ME_ERRNO_SIGNAL;
 202        }
 203
 204        spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
 205        instance->rised = 0;
 206        *irq_count = instance->n;
 207        *value = 1;
 208        spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
 209
 210        ME_SUBDEVICE_EXIT;
 211
 212        return err;
 213}
 214
 215static int me1400_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
 216                                      struct file *filep,
 217                                      int channel, int flags)
 218{
 219        me1400_ext_irq_subdevice_t *instance;
 220        unsigned long cpu_flags;
 221        uint8_t tmp;
 222        int err = ME_ERRNO_SUCCESS;
 223
 224        PDEBUG("executed.\n");
 225
 226        instance = (me1400_ext_irq_subdevice_t *) subdevice;
 227
 228        if (flags) {
 229                PERROR("Invalid flag specified.\n");
 230                return ME_ERRNO_INVALID_FLAGS;
 231        }
 232
 233        if (channel) {
 234                PERROR("Invalid channel.\n");
 235                return ME_ERRNO_INVALID_CHANNEL;
 236        }
 237
 238        ME_SUBDEVICE_ENTER;
 239
 240        spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
 241        spin_lock(instance->clk_src_reg_lock);
 242//                      // Disable IRQ on PLX
 243//                      tmp = inb(instance->plx_intcs_reg) & ( ~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN));
 244//                      outb(tmp, instance->plx_intcs_reg);
 245//                      PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
 246
 247        switch (instance->device_id) {
 248        case PCI_DEVICE_ID_MEILHAUS_ME140C:
 249        case PCI_DEVICE_ID_MEILHAUS_ME140D:
 250                tmp = inb(instance->ctrl_reg);
 251                tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
 252                outb(tmp, instance->ctrl_reg);
 253                PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
 254                           instance->reg_base,
 255                           instance->ctrl_reg - instance->reg_base, tmp);
 256
 257                break;
 258
 259        default:
 260                outb(0x00, instance->ctrl_reg);
 261                PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
 262                           instance->reg_base,
 263                           instance->ctrl_reg - instance->reg_base, 0x00);
 264                break;
 265        }
 266        spin_unlock(instance->clk_src_reg_lock);
 267        instance->rised = -1;
 268        spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
 269        wake_up_interruptible_all(&instance->wait_queue);
 270
 271        ME_SUBDEVICE_EXIT;
 272
 273        return err;
 274}
 275
 276static int me1400_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
 277                                             struct file *filep, int flags)
 278{
 279        me1400_ext_irq_subdevice_t *instance =
 280            (me1400_ext_irq_subdevice_t *) subdevice;
 281
 282        PDEBUG("executed.\n");
 283
 284        if (flags) {
 285                PERROR("Invalid flag specified.\n");
 286                return ME_ERRNO_INVALID_FLAGS;
 287        }
 288
 289        instance->n = 0;
 290        return me1400_ext_irq_io_irq_stop(subdevice, filep, 0, flags);
 291}
 292
 293static int me1400_ext_irq_query_number_channels(struct me_subdevice *subdevice,
 294                                                int *number)
 295{
 296        PDEBUG("executed.\n");
 297        *number = ME1400_EXT_IRQ_NUMBER_CHANNELS;
 298        return ME_ERRNO_SUCCESS;
 299}
 300
 301static int me1400_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
 302                                               int *type, int *subtype)
 303{
 304        PDEBUG("executed.\n");
 305        *type = ME_TYPE_EXT_IRQ;
 306        *subtype = ME_SUBTYPE_SINGLE;
 307        return ME_ERRNO_SUCCESS;
 308}
 309
 310static int me1400_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
 311                                               int *caps)
 312{
 313        PDEBUG("executed.\n");
 314        *caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
 315        return ME_ERRNO_SUCCESS;
 316}
 317
 318static int me1400_ext_irq_query_subdevice_caps_args(struct me_subdevice
 319                                                    *subdevice, int cap,
 320                                                    int *args, int count)
 321{
 322        PDEBUG("executed.\n");
 323        return ME_ERRNO_NOT_SUPPORTED;
 324}
 325
 326#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 327static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id)
 328#else
 329static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id,
 330                                      struct pt_regs *regs)
 331#endif
 332{
 333        me1400_ext_irq_subdevice_t *instance;
 334        uint32_t status;
 335        uint8_t tmp;
 336
 337        instance = (me1400_ext_irq_subdevice_t *) dev_id;
 338
 339        if (irq != instance->irq) {
 340                PERROR("Incorrect interrupt num: %d.\n", irq);
 341                return IRQ_NONE;
 342        }
 343
 344        spin_lock(&instance->subdevice_lock);
 345        status = inl(instance->plx_intcs_reg);
 346//              if (!((status & PLX_LOCAL_INT1_STATE) && (status & PLX_LOCAL_INT1_EN) && (status & PLX_PCI_INT_EN)))
 347        if ((status &
 348             (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) !=
 349            (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) {
 350                spin_unlock(&instance->subdevice_lock);
 351                PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
 352                      jiffies, __func__, status);
 353                return IRQ_NONE;
 354        }
 355
 356        inl(instance->ctrl_reg);
 357
 358        PDEBUG("executed.\n");
 359
 360        instance->n++;
 361        instance->rised = 1;
 362
 363        switch (instance->device_id) {
 364
 365        case PCI_DEVICE_ID_MEILHAUS_ME140C:
 366        case PCI_DEVICE_ID_MEILHAUS_ME140D:
 367                spin_lock(instance->clk_src_reg_lock);
 368                tmp = inb(instance->ctrl_reg);
 369                tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
 370                outb(tmp, instance->ctrl_reg);
 371                PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
 372                           instance->reg_base,
 373                           instance->ctrl_reg - instance->reg_base, tmp);
 374                tmp |= ME1400CD_EXT_IRQ_CLK_EN;
 375                outb(tmp, instance->ctrl_reg);
 376                PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
 377                           instance->reg_base,
 378                           instance->ctrl_reg - instance->reg_base, tmp);
 379                spin_unlock(instance->clk_src_reg_lock);
 380
 381                break;
 382
 383        default:
 384                outb(0, instance->ctrl_reg);
 385                PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
 386                           instance->reg_base,
 387                           instance->ctrl_reg - instance->reg_base, 0);
 388                outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
 389                PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
 390                           instance->reg_base,
 391                           instance->ctrl_reg - instance->reg_base,
 392                           ME1400AB_EXT_IRQ_IRQ_EN);
 393                break;
 394        }
 395
 396        spin_unlock(&instance->subdevice_lock);
 397        wake_up_interruptible_all(&instance->wait_queue);
 398
 399        return IRQ_HANDLED;
 400}
 401
 402static void me1400_ext_irq_destructor(struct me_subdevice *subdevice)
 403{
 404        me1400_ext_irq_subdevice_t *instance;
 405        uint8_t tmp;
 406
 407        PDEBUG("executed.\n");
 408
 409        instance = (me1400_ext_irq_subdevice_t *) subdevice;
 410
 411        // Disable IRQ on PLX
 412        tmp =
 413            inb(instance->
 414                plx_intcs_reg) & (~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
 415                                    PLX_PCI_INT_EN));
 416        outb(tmp, instance->plx_intcs_reg);
 417        PDEBUG_REG("ctrl_reg outb(plx:0x%lX)=0x%x\n", instance->plx_intcs_reg,
 418                   tmp);
 419
 420        free_irq(instance->irq, (void *)instance);
 421        me_subdevice_deinit(&instance->base);
 422        kfree(instance);
 423}
 424
 425me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id,
 426                                                       uint32_t plx_reg_base,
 427                                                       uint32_t me1400_reg_base,
 428                                                       spinlock_t *
 429                                                       clk_src_reg_lock,
 430                                                       int irq)
 431{
 432        me1400_ext_irq_subdevice_t *subdevice;
 433        int err;
 434        uint8_t tmp;
 435
 436        PDEBUG("executed.\n");
 437
 438        /* Allocate memory for subdevice instance */
 439        subdevice = kmalloc(sizeof(me1400_ext_irq_subdevice_t), GFP_KERNEL);
 440
 441        if (!subdevice) {
 442                PERROR("Cannot get memory for 1400_ext_irq instance.\n");
 443                return NULL;
 444        }
 445
 446        memset(subdevice, 0, sizeof(me1400_ext_irq_subdevice_t));
 447
 448        /* Initialize subdevice base class */
 449        err = me_subdevice_init(&subdevice->base);
 450
 451        if (err) {
 452                PERROR("Cannot initialize subdevice base class instance.\n");
 453                kfree(subdevice);
 454                return NULL;
 455        }
 456        // Initialize spin locks.
 457        spin_lock_init(&subdevice->subdevice_lock);
 458        subdevice->clk_src_reg_lock = clk_src_reg_lock;
 459
 460        /* Initialize wait queue */
 461        init_waitqueue_head(&subdevice->wait_queue);
 462
 463        subdevice->irq = irq;
 464
 465        err = request_irq(irq, me1400_ext_irq_isr,
 466#ifdef IRQF_DISABLED
 467                          IRQF_DISABLED | IRQF_SHARED,
 468#else
 469                          SA_INTERRUPT | SA_SHIRQ,
 470#endif
 471                          ME1400_NAME, (void *)subdevice);
 472
 473        if (err) {
 474                PERROR("Can't get irq.\n");
 475                me_subdevice_deinit(&subdevice->base);
 476                kfree(subdevice);
 477                return NULL;
 478        }
 479        PINFO("Registered irq=%d.\n", subdevice->irq);
 480
 481        /* Initialize registers */
 482        subdevice->plx_intcs_reg = plx_reg_base + PLX_INTCSR_REG;
 483        subdevice->ctrl_reg = me1400_reg_base + ME1400AB_EXT_IRQ_CTRL_REG;
 484#ifdef MEDEBUG_DEBUG_REG
 485        subdevice->reg_base = me1400_reg_base;
 486#endif
 487
 488        // Enable IRQ on PLX
 489        tmp =
 490            inb(subdevice->
 491                plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
 492                                  PLX_PCI_INT_EN);
 493        outb(tmp, subdevice->plx_intcs_reg);
 494        PDEBUG_REG("ctrl_reg outb(Pplx:0x%lX)=0x%x\n", subdevice->plx_intcs_reg,
 495                   tmp);
 496
 497        /* Initialize the subdevice methods */
 498        subdevice->base.me_subdevice_io_irq_start = me1400_ext_irq_io_irq_start;
 499        subdevice->base.me_subdevice_io_irq_wait = me1400_ext_irq_io_irq_wait;
 500        subdevice->base.me_subdevice_io_irq_stop = me1400_ext_irq_io_irq_stop;
 501        subdevice->base.me_subdevice_io_reset_subdevice =
 502            me1400_ext_irq_io_reset_subdevice;
 503        subdevice->base.me_subdevice_query_number_channels =
 504            me1400_ext_irq_query_number_channels;
 505        subdevice->base.me_subdevice_query_subdevice_type =
 506            me1400_ext_irq_query_subdevice_type;
 507        subdevice->base.me_subdevice_query_subdevice_caps =
 508            me1400_ext_irq_query_subdevice_caps;
 509        subdevice->base.me_subdevice_query_subdevice_caps_args =
 510            me1400_ext_irq_query_subdevice_caps_args;
 511        subdevice->base.me_subdevice_destructor = me1400_ext_irq_destructor;
 512
 513        subdevice->rised = 0;
 514        subdevice->n = 0;
 515
 516        return subdevice;
 517}
 518
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.