linux/drivers/staging/meilhaus/me8200_di.c
<<
>>
Prefs
   1/**
   2 * @file me8200_di.c
   3 *
   4 * @brief ME-8200 digital input 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///Includes
  33#include <linux/module.h>
  34
  35#include <linux/slab.h>
  36#include <linux/spinlock.h>
  37#include <asm/io.h>
  38#include <linux/types.h>
  39#include <linux/interrupt.h>
  40#include <linux/version.h>
  41
  42#include "medefines.h"
  43#include "meerror.h"
  44
  45#include "meids.h"
  46#include "medebug.h"
  47#include "me8200_reg.h"
  48#include "me8200_di_reg.h"
  49#include "me8200_di.h"
  50
  51/// Defines
  52static void me8200_di_destructor(struct me_subdevice *subdevice);
  53static int me8200_di_io_irq_start(me_subdevice_t * subdevice,
  54                                  struct file *filep,
  55                                  int channel,
  56                                  int irq_source,
  57                                  int irq_edge, int irq_arg, int flags);
  58static int me8200_di_io_irq_wait(me_subdevice_t * subdevice,
  59                                 struct file *filep,
  60                                 int channel,
  61                                 int *irq_count,
  62                                 int *value, int time_out, int flags);
  63static int me8200_di_io_irq_stop(me_subdevice_t * subdevice,
  64                                 struct file *filep, int channel, int flags);
  65static int me8200_di_io_single_config(me_subdevice_t * subdevice,
  66                                      struct file *filep,
  67                                      int channel,
  68                                      int single_config,
  69                                      int ref,
  70                                      int trig_chan,
  71                                      int trig_type, int trig_edge, int flags);
  72static int me8200_di_io_single_read(me_subdevice_t * subdevice,
  73                                    struct file *filep,
  74                                    int channel,
  75                                    int *value, int time_out, int flags);
  76static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice,
  77                                        struct file *filep, int flags);
  78static int me8200_di_query_number_channels(me_subdevice_t * subdevice,
  79                                           int *number);
  80static int me8200_di_query_subdevice_type(me_subdevice_t * subdevice,
  81                                          int *type, int *subtype);
  82static int me8200_di_query_subdevice_caps(me_subdevice_t * subdevice,
  83                                          int *caps);
  84#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
  85static irqreturn_t me8200_isr(int irq, void *dev_id);
  86#else
  87static irqreturn_t me8200_isr(int irq, void *dev_id, struct pt_regs *regs);
  88#endif
  89#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
  90static irqreturn_t me8200_isr_EX(int irq, void *dev_id);
  91#else
  92static irqreturn_t me8200_isr_EX(int irq, void *dev_id, struct pt_regs *regs);
  93#endif
  94static void me8200_di_check_version(me8200_di_subdevice_t * instance,
  95                                    unsigned long addr);
  96
  97///Functions
  98static int me8200_di_io_irq_start(me_subdevice_t * subdevice,
  99                                  struct file *filep,
 100                                  int channel,
 101                                  int irq_source,
 102                                  int irq_edge, int irq_arg, int flags)
 103{
 104        me8200_di_subdevice_t *instance;
 105        int err = ME_ERRNO_SUCCESS;
 106        volatile uint8_t tmp;
 107        unsigned long status;
 108
 109        PDEBUG("executed.\n");
 110
 111        instance = (me8200_di_subdevice_t *) subdevice;
 112
 113        if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
 114                if (flags &
 115                    ~(ME_IO_IRQ_START_PATTERN_FILTERING |
 116                      ME_IO_IRQ_START_DIO_BYTE)) {
 117                        PERROR("Invalid flag specified.\n");
 118                        return ME_ERRNO_INVALID_FLAGS;
 119                }
 120
 121                if (irq_edge != ME_IRQ_EDGE_NOT_USED) {
 122                        PERROR("Invalid irq edge specified.\n");
 123                        return ME_ERRNO_INVALID_IRQ_EDGE;
 124                }
 125        } else if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
 126                if (flags &
 127                    ~(ME_IO_IRQ_START_EXTENDED_STATUS |
 128                      ME_IO_IRQ_START_DIO_BYTE)) {
 129                        PERROR("Invalid flag specified.\n");
 130                        return ME_ERRNO_INVALID_FLAGS;
 131                }
 132
 133                if ((irq_edge != ME_IRQ_EDGE_RISING)
 134                    && (irq_edge != ME_IRQ_EDGE_FALLING)
 135                    && (irq_edge != ME_IRQ_EDGE_ANY)) {
 136                        PERROR("Invalid irq edge specified.\n");
 137                        return ME_ERRNO_INVALID_IRQ_EDGE;
 138                }
 139
 140                if (!(irq_arg & 0xFF)) {
 141                        PERROR("No mask specified.\n");
 142                        return ME_ERRNO_INVALID_IRQ_ARG;
 143                }
 144        } else {
 145                PERROR("Invalid irq source specified.\n");
 146                return ME_ERRNO_INVALID_IRQ_SOURCE;
 147        }
 148
 149        if (channel) {
 150                PERROR("Invalid channel specified.\n");
 151                return ME_ERRNO_INVALID_CHANNEL;
 152        }
 153
 154        ME_SUBDEVICE_ENTER;
 155
 156        spin_lock_irqsave(&instance->subdevice_lock, status);
 157        if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
 158                outb(irq_arg, instance->compare_reg);
 159                PDEBUG_REG("compare_reg outb(0x%lX+0x%lX)=0x%x\n",
 160                           instance->reg_base,
 161                           instance->compare_reg - instance->reg_base, irq_arg);
 162                outb(0xFF, instance->mask_reg);
 163                PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n",
 164                           instance->reg_base,
 165                           instance->mask_reg - instance->reg_base, 0xff);
 166                instance->compare_value = irq_arg;
 167                instance->filtering_flag =
 168                    (flags & ME_IO_IRQ_START_PATTERN_FILTERING) ? 1 : 0;
 169        }
 170        if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
 171                outb(irq_arg, instance->mask_reg);
 172                PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n",
 173                           instance->reg_base,
 174                           instance->mask_reg - instance->reg_base, irq_arg);
 175                instance->filtering_flag = 0;
 176        }
 177
 178        spin_lock(instance->irq_mode_lock);
 179        tmp = inb(instance->irq_mode_reg);
 180        tmp &=
 181            ~(ME8200_IRQ_MODE_MASK <<
 182              (ME8200_IRQ_MODE_DI_SHIFT * instance->di_idx));
 183        if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
 184                tmp |=
 185                    ME8200_IRQ_MODE_MASK_COMPARE << (ME8200_IRQ_MODE_DI_SHIFT *
 186                                                     instance->di_idx);
 187        }
 188
 189        if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
 190                tmp |=
 191                    ME8200_IRQ_MODE_MASK_MASK << (ME8200_IRQ_MODE_DI_SHIFT *
 192                                                  instance->di_idx);
 193        }
 194        outb(tmp, instance->irq_mode_reg);
 195        PDEBUG_REG("irq_mode_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 196                   instance->irq_mode_reg - instance->reg_base, tmp);
 197        spin_unlock(instance->irq_mode_lock);
 198
 199        spin_lock(instance->irq_ctrl_lock);
 200        tmp = inb(instance->irq_ctrl_reg);
 201        tmp |=
 202            (ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
 203             (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 204        tmp |=
 205            ME8200_DI_IRQ_CTRL_BIT_ENABLE << (ME8200_DI_IRQ_CTRL_SHIFT *
 206                                              instance->di_idx);
 207
 208        if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
 209                tmp &=
 210                    ~(ME8200_DI_IRQ_CTRL_MASK_EDGE <<
 211                      (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 212                if (irq_edge == ME_IRQ_EDGE_RISING) {
 213                        tmp |=
 214                            ME8200_DI_IRQ_CTRL_MASK_EDGE_RISING <<
 215                            (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
 216                } else if (irq_edge == ME_IRQ_EDGE_FALLING) {
 217                        tmp |=
 218                            ME8200_DI_IRQ_CTRL_MASK_EDGE_FALLING <<
 219                            (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
 220                } else if (irq_edge == ME_IRQ_EDGE_ANY) {
 221                        tmp |=
 222                            ME8200_DI_IRQ_CTRL_MASK_EDGE_ANY <<
 223                            (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
 224                }
 225        }
 226        outb(tmp, instance->irq_ctrl_reg);
 227        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 228                   instance->irq_ctrl_reg - instance->reg_base, tmp);
 229        tmp &=
 230            ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
 231              (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 232        outb(tmp, instance->irq_ctrl_reg);
 233        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 234                   instance->irq_ctrl_reg - instance->reg_base, tmp);
 235
 236        instance->line_value = inb(instance->port_reg);
 237        spin_unlock(instance->irq_ctrl_lock);
 238
 239        instance->rised = 0;
 240        instance->status_value = 0;
 241        instance->status_value_edges = 0;
 242        instance->status_flag = flags & ME_IO_IRQ_START_EXTENDED_STATUS;
 243        spin_unlock_irqrestore(&instance->subdevice_lock, status);
 244        ME_SUBDEVICE_EXIT;
 245
 246        return err;
 247}
 248
 249static int me8200_di_io_irq_wait(me_subdevice_t * subdevice,
 250                                 struct file *filep,
 251                                 int channel,
 252                                 int *irq_count,
 253                                 int *value, int time_out, int flags)
 254{
 255        me8200_di_subdevice_t *instance;
 256        int err = ME_ERRNO_SUCCESS;
 257        long t = 0;
 258        unsigned long cpu_flags;
 259        int count;
 260
 261        PDEBUG("executed.\n");
 262        PDEVELOP("PID: %d.\n", current->pid);
 263
 264        instance = (me8200_di_subdevice_t *) subdevice;
 265
 266        if (flags &
 267            ~(ME_IO_IRQ_WAIT_NORMAL_STATUS | ME_IO_IRQ_WAIT_EXTENDED_STATUS)) {
 268                PERROR("Invalid flag specified.\n");
 269                return ME_ERRNO_INVALID_FLAGS;
 270        }
 271
 272        if (channel) {
 273                PERROR("Invalid channel specified.\n");
 274                return ME_ERRNO_INVALID_CHANNEL;
 275        }
 276
 277        if (time_out < 0) {
 278                PERROR("Invalid time_out specified.\n");
 279                return ME_ERRNO_INVALID_TIMEOUT;
 280        }
 281
 282        if (time_out) {
 283                t = (time_out * HZ) / 1000;
 284
 285                if (t == 0)
 286                        t = 1;
 287        }
 288
 289        ME_SUBDEVICE_ENTER;
 290
 291        if (instance->rised <= 0) {
 292                instance->rised = 0;
 293                count = instance->count;
 294
 295                if (time_out) {
 296                        t = wait_event_interruptible_timeout(instance->
 297                                                             wait_queue,
 298                                                             ((count !=
 299                                                               instance->count)
 300                                                              || (instance->
 301                                                                  rised < 0)),
 302                                                             t);
 303//                      t = wait_event_interruptible_timeout(instance->wait_queue, (instance->rised != 0), t);
 304                        if (t == 0) {
 305                                PERROR("Wait on interrupt timed out.\n");
 306                                err = ME_ERRNO_TIMEOUT;
 307                        }
 308                } else {
 309                        wait_event_interruptible(instance->wait_queue,
 310                                                 ((count != instance->count)
 311                                                  || (instance->rised < 0)));
 312//                      wait_event_interruptible(instance->wait_queue, (instance->rised != 0));
 313                }
 314
 315                if (instance->rised < 0) {
 316                        PERROR("Wait on interrupt aborted by user.\n");
 317                        err = ME_ERRNO_CANCELLED;
 318                }
 319        }
 320
 321        if (signal_pending(current)) {
 322                PERROR("Wait on interrupt aborted by signal.\n");
 323                err = ME_ERRNO_SIGNAL;
 324        }
 325
 326        spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
 327        *irq_count = instance->count;
 328        if (!err) {
 329                if (flags & ME_IO_IRQ_WAIT_NORMAL_STATUS) {
 330                        *value = instance->status_value;
 331                } else if (flags & ME_IO_IRQ_WAIT_EXTENDED_STATUS) {
 332                        *value = instance->status_value_edges;
 333                } else {        // Use default
 334                        if (!instance->status_flag) {
 335                                *value = instance->status_value;
 336                        } else {
 337                                *value = instance->status_value_edges;
 338                        }
 339                }
 340                instance->rised = 0;
 341/*
 342                        instance->status_value = 0;
 343                        instance->status_value_edges = 0;
 344*/
 345        } else {
 346                *value = 0;
 347        }
 348        spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
 349
 350        ME_SUBDEVICE_EXIT;
 351
 352        return err;
 353}
 354
 355static int me8200_di_io_irq_stop(me_subdevice_t * subdevice,
 356                                 struct file *filep, int channel, int flags)
 357{
 358        me8200_di_subdevice_t *instance;
 359        uint8_t tmp;
 360        unsigned long status;
 361
 362        PDEBUG("executed.\n");
 363
 364        instance = (me8200_di_subdevice_t *) subdevice;
 365
 366        if (flags) {
 367                PERROR("Invalid flag specified.\n");
 368                return ME_ERRNO_INVALID_FLAGS;
 369        }
 370
 371        if (channel) {
 372                PERROR("Invalid channel specified.\n");
 373                return ME_ERRNO_INVALID_CHANNEL;
 374        }
 375
 376        ME_SUBDEVICE_ENTER spin_lock_irqsave(&instance->subdevice_lock, status);
 377        spin_lock(instance->irq_ctrl_lock);
 378        tmp = inb(instance->irq_ctrl_reg);
 379        tmp |=
 380            (ME8200_DI_IRQ_CTRL_BIT_ENABLE <<
 381             (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 382        outb(tmp, instance->irq_ctrl_reg);
 383        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 384                   instance->irq_ctrl_reg - instance->reg_base, tmp);
 385        tmp &=
 386            ~(ME8200_DI_IRQ_CTRL_BIT_ENABLE <<
 387              (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 388        tmp |=
 389            (ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
 390             (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 391//                      tmp &= ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 392        outb(tmp, instance->irq_ctrl_reg);
 393        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 394                   instance->irq_ctrl_reg - instance->reg_base, tmp);
 395        spin_unlock(instance->irq_ctrl_lock);
 396
 397        instance->rised = -1;
 398        instance->status_value = 0;
 399        instance->status_value_edges = 0;
 400        instance->filtering_flag = 0;
 401        spin_unlock_irqrestore(&instance->subdevice_lock, status);
 402        wake_up_interruptible_all(&instance->wait_queue);
 403
 404        ME_SUBDEVICE_EXIT;
 405
 406        return ME_ERRNO_SUCCESS;
 407}
 408
 409static int me8200_di_io_single_config(me_subdevice_t * subdevice,
 410                                      struct file *filep,
 411                                      int channel,
 412                                      int single_config,
 413                                      int ref,
 414                                      int trig_chan,
 415                                      int trig_type, int trig_edge, int flags)
 416{
 417        me8200_di_subdevice_t *instance;
 418        int err = ME_ERRNO_SUCCESS;
 419        unsigned long status;
 420
 421        PDEBUG("executed.\n");
 422
 423        instance = (me8200_di_subdevice_t *) subdevice;
 424
 425        ME_SUBDEVICE_ENTER;
 426
 427        spin_lock_irqsave(&instance->subdevice_lock, status);
 428
 429        switch (flags) {
 430        case ME_IO_SINGLE_CONFIG_NO_FLAGS:
 431        case ME_IO_SINGLE_CONFIG_DIO_BYTE:
 432                if (channel == 0) {
 433                        if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
 434                        } else {
 435                                PERROR("Invalid port direction specified.\n");
 436                                err = ME_ERRNO_INVALID_SINGLE_CONFIG;
 437                        }
 438                } else {
 439                        PERROR("Invalid channel number.\n");
 440                        err = ME_ERRNO_INVALID_CHANNEL;
 441                }
 442                break;
 443
 444        default:
 445                PERROR("Invalid flags specified.\n");
 446                err = ME_ERRNO_INVALID_FLAGS;
 447        }
 448
 449        spin_unlock_irqrestore(&instance->subdevice_lock, status);
 450
 451        ME_SUBDEVICE_EXIT;
 452
 453        return err;
 454}
 455
 456static int me8200_di_io_single_read(me_subdevice_t * subdevice,
 457                                    struct file *filep,
 458                                    int channel,
 459                                    int *value, int time_out, int flags)
 460{
 461        me8200_di_subdevice_t *instance;
 462        int err = ME_ERRNO_SUCCESS;
 463        unsigned long status;
 464
 465        PDEBUG("executed.\n");
 466
 467        instance = (me8200_di_subdevice_t *) subdevice;
 468
 469        ME_SUBDEVICE_ENTER;
 470
 471        spin_lock_irqsave(&instance->subdevice_lock, status);
 472
 473        switch (flags) {
 474        case ME_IO_SINGLE_TYPE_DIO_BIT:
 475                if ((channel >= 0) && (channel < 8)) {
 476                        *value = inb(instance->port_reg) & (0x1 << channel);
 477                } else {
 478                        PERROR("Invalid bit number specified.\n");
 479                        err = ME_ERRNO_INVALID_CHANNEL;
 480                }
 481                break;
 482
 483        case ME_IO_SINGLE_NO_FLAGS:
 484        case ME_IO_SINGLE_TYPE_DIO_BYTE:
 485                if (channel == 0) {
 486                        *value = inb(instance->port_reg);
 487                } else {
 488                        PERROR("Invalid channel number.\n");
 489                        err = ME_ERRNO_INVALID_CHANNEL;
 490                }
 491                break;
 492
 493        default:
 494                PERROR("Invalid flags specified.\n");
 495                err = ME_ERRNO_INVALID_FLAGS;
 496        }
 497
 498        spin_unlock_irqrestore(&instance->subdevice_lock, status);
 499
 500        ME_SUBDEVICE_EXIT;
 501
 502        return err;
 503}
 504
 505static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice,
 506                                        struct file *filep, int flags)
 507{
 508        me8200_di_subdevice_t *instance = (me8200_di_subdevice_t *) subdevice;
 509
 510        PDEBUG("executed.\n");
 511
 512        if (flags) {
 513                PERROR("Invalid flag specified.\n");
 514                return ME_ERRNO_INVALID_FLAGS;
 515        }
 516
 517        instance->count = 0;
 518        return me8200_di_io_irq_stop(subdevice, filep, 0, 0);
 519}
 520
 521static int me8200_di_query_number_channels(me_subdevice_t * subdevice,
 522                                           int *number)
 523{
 524        PDEBUG("executed.\n");
 525        *number = 8;
 526        return ME_ERRNO_SUCCESS;
 527}
 528
 529static int me8200_di_query_subdevice_type(me_subdevice_t * subdevice,
 530                                          int *type, int *subtype)
 531{
 532        PDEBUG("executed.\n");
 533        *type = ME_TYPE_DI;
 534        *subtype = ME_SUBTYPE_SINGLE;
 535        return ME_ERRNO_SUCCESS;
 536}
 537
 538static int me8200_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps)
 539{
 540        PDEBUG("executed.\n");
 541        *caps =
 542            ME_CAPS_DIO_BIT_PATTERN_IRQ |
 543            ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_RISING |
 544            ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_FALLING |
 545            ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY;
 546        return ME_ERRNO_SUCCESS;
 547}
 548
 549#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 550static irqreturn_t me8200_isr(int irq, void *dev_id)
 551#else
 552static irqreturn_t me8200_isr(int irq, void *dev_id, struct pt_regs *regs)
 553#endif
 554{
 555        me8200_di_subdevice_t *instance;
 556        uint8_t ctrl;
 557        uint8_t irq_status;
 558        uint8_t line_value = 0;
 559        uint8_t line_status = 0;
 560        uint32_t status_val = 0;
 561
 562        instance = (me8200_di_subdevice_t *) dev_id;
 563
 564        if (irq != instance->irq) {
 565                PERROR("Incorrect interrupt num: %d.\n", irq);
 566                return IRQ_NONE;
 567        }
 568
 569        irq_status = inb(instance->irq_status_reg);
 570        if (!irq_status) {
 571                PINFO
 572                    ("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
 573                     jiffies, __func__, instance->di_idx, irq_status);
 574                return IRQ_NONE;
 575        }
 576
 577        PDEBUG("executed.\n");
 578
 579        spin_lock(&instance->subdevice_lock);
 580        spin_lock(instance->irq_ctrl_lock);
 581        ctrl = inb(instance->irq_ctrl_reg);
 582        ctrl |=
 583            ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT *
 584                                             instance->di_idx);
 585        outb(ctrl, instance->irq_ctrl_reg);
 586        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 587                   instance->irq_ctrl_reg - instance->reg_base, ctrl);
 588        ctrl &=
 589            ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
 590              (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
 591        outb(ctrl, instance->irq_ctrl_reg);
 592        PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
 593                   instance->irq_ctrl_reg - instance->reg_base, ctrl);
 594
 595        line_value = inb(instance->port_reg);
 596        spin_unlock(instance->irq_ctrl_lock);
 597
 598        line_status = ((uint8_t) instance->line_value ^ line_value);
 599
 600        // Make extended information.
 601        status_val |= (0x00FF & (~(uint8_t) instance->line_value & line_value)) << 16;  //Raise
 602        status_val |= (0x00FF & ((uint8_t) instance->line_value & ~line_value));        //Fall
 603
 604        instance->line_value = (int)line_value;
 605
 606        if (instance->rised == 0) {
 607                instance->status_value = irq_status | line_status;
 608                instance->status_value_edges = status_val;
 609        } else {
 610                instance->status_value |= irq_status | line_status;
 611                instance->status_value_edges |= status_val;
 612        }
 613
 614        if (instance->filtering_flag) { // For compare mode only.
 615                if (instance->compare_value == instance->line_value) {
 616                        instance->rised = 1;
 617                        instance->count++;
 618                }
 619        } else {
 620                instance->rised = 1;
 621                instance->count++;
 622        }
 623        spin_unlock(&instance->subdevice_lock);
 624
 625        spin_unlock(&instance->subdevice_lock);
 626
 627        wake_up_interruptible_all(&instance->wait_queue);
 628
 629        return IRQ_HANDLED;
 630}
 631
 632#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 633static irqreturn_t me8200_isr_EX(int irq, void *dev_id)
 634#else
 635static irqreturn_t me8200_isr_EX(int irq, void *dev_id, struct pt_regs *regs)
 636#endif
 637{
 638        me8200_di_subdevice_t *instance;
 639        uint8_t irq_status = 0;
 640        uint16_t irq_status_EX = 0;
 641        uint32_t status_val = 0;
 642        int i, j;
 643
 644        instance = (me8200_di_subdevice_t *) dev_id;
 645
 646        if (irq != instance->irq) {
 647                PERROR("Incorrect interrupt num: %d.\n", irq);
 648                return IRQ_NONE;
 649        }
 650
 651        PDEBUG("executed.\n");
 652
 653        //Reset latches. Copy status to extended registers.
 654        irq_status = inb(instance->irq_status_reg);
 655        PDEBUG_REG("idx=%d irq_status_reg=0x%02X\n", instance->di_idx,
 656                   irq_status);
 657
 658        if (!irq_status) {
 659                PINFO
 660                    ("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
 661                     jiffies, __func__, instance->di_idx, irq_status);
 662                return IRQ_NONE;
 663        }
 664
 665        irq_status_EX = inb(instance->irq_status_low_reg);
 666        irq_status_EX |= (inb(instance->irq_status_high_reg) << 8);
 667
 668        PDEVELOP("EXTENDED REG: 0x%04x\n", irq_status_EX);
 669        instance->line_value = inb(instance->port_reg);
 670
 671        // Format extended information.
 672        for (i = 0, j = 0; i < 8; i++, j += 2) {
 673                status_val |= ((0x01 << j) & irq_status_EX) >> (j - i); //Fall
 674                status_val |= ((0x01 << (j + 1)) & irq_status_EX) << (15 - j + i);      //Raise
 675        }
 676
 677        spin_lock(&instance->subdevice_lock);
 678        if (instance->rised == 0) {
 679                instance->status_value = irq_status;
 680                instance->status_value_edges = status_val;
 681        } else {
 682                instance->status_value |= irq_status;
 683                instance->status_value_edges |= status_val;
 684        }
 685
 686        if (instance->filtering_flag) { // For compare mode only.
 687                if (instance->compare_value == instance->line_value) {
 688                        instance->rised = 1;
 689                        instance->count++;
 690                }
 691        } else {
 692                instance->rised = 1;
 693                instance->count++;
 694        }
 695        spin_unlock(&instance->subdevice_lock);
 696
 697        wake_up_interruptible_all(&instance->wait_queue);
 698
 699        return IRQ_HANDLED;
 700}
 701
 702static void me8200_di_destructor(struct me_subdevice *subdevice)
 703{
 704        me8200_di_subdevice_t *instance;
 705
 706        PDEBUG("executed.\n");
 707
 708        instance = (me8200_di_subdevice_t *) subdevice;
 709
 710        free_irq(instance->irq, (void *)instance);
 711        me_subdevice_deinit(&instance->base);
 712        kfree(instance);
 713}
 714
 715me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_regbase,
 716                                             unsigned int di_idx,
 717                                             int irq,
 718                                             spinlock_t * irq_ctrl_lock,
 719                                             spinlock_t * irq_mode_lock)
 720{
 721        me8200_di_subdevice_t *subdevice;
 722        int err;
 723
 724        PDEBUG("executed.\n");
 725
 726        /* Allocate memory for subdevice instance */
 727        subdevice = kmalloc(sizeof(me8200_di_subdevice_t), GFP_KERNEL);
 728
 729        if (!subdevice) {
 730                PERROR("Cannot get memory for subdevice instance.\n");
 731                return NULL;
 732        }
 733
 734        memset(subdevice, 0, sizeof(me8200_di_subdevice_t));
 735
 736        /* Initialize subdevice base class */
 737        err = me_subdevice_init(&subdevice->base);
 738
 739        if (err) {
 740                PERROR("Cannot initialize subdevice base class instance.\n");
 741                kfree(subdevice);
 742                return NULL;
 743        }
 744        // Check firmware version.
 745        me8200_di_check_version(subdevice,
 746                                me8200_regbase + ME8200_FIRMWARE_VERSION_REG);
 747
 748        // Initialize spin locks.
 749        spin_lock_init(&subdevice->subdevice_lock);
 750
 751        subdevice->irq_ctrl_lock = irq_ctrl_lock;
 752        subdevice->irq_mode_lock = irq_mode_lock;
 753
 754        /* Save the subdevice index. */
 755        subdevice->di_idx = di_idx;
 756
 757        /* Initialize registers */
 758        if (di_idx == 0) {
 759                subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_0_REG;
 760                subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_0_REG;
 761                subdevice->compare_reg =
 762                    me8200_regbase + ME8200_DI_COMPARE_0_REG;
 763                subdevice->irq_status_reg =
 764                    me8200_regbase + ME8200_DI_CHANGE_0_REG;
 765
 766                subdevice->irq_status_low_reg =
 767                    me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_LOW_REG;
 768                subdevice->irq_status_high_reg =
 769                    me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_HIGH_REG;
 770        } else if (di_idx == 1) {
 771                subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_1_REG;
 772                subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_1_REG;
 773                subdevice->compare_reg =
 774                    me8200_regbase + ME8200_DI_COMPARE_1_REG;
 775                subdevice->irq_status_reg =
 776                    me8200_regbase + ME8200_DI_CHANGE_1_REG;
 777
 778                subdevice->irq_status_low_reg =
 779                    me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_LOW_REG;
 780                subdevice->irq_status_high_reg =
 781                    me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_HIGH_REG;
 782        } else {
 783                PERROR("Wrong subdevice idx=%d.\n", di_idx);
 784                kfree(subdevice);
 785                return NULL;
 786        }
 787        subdevice->irq_ctrl_reg = me8200_regbase + ME8200_DI_IRQ_CTRL_REG;
 788        subdevice->irq_mode_reg = me8200_regbase + ME8200_IRQ_MODE_REG;
 789#ifdef MEDEBUG_DEBUG_REG
 790        subdevice->reg_base = me8200_regbase;
 791#endif
 792
 793        /* Initialize wait queue */
 794        init_waitqueue_head(&subdevice->wait_queue);
 795
 796        /* Overload base class methods. */
 797        subdevice->base.me_subdevice_io_irq_start = me8200_di_io_irq_start;
 798        subdevice->base.me_subdevice_io_irq_wait = me8200_di_io_irq_wait;
 799        subdevice->base.me_subdevice_io_irq_stop = me8200_di_io_irq_stop;
 800        subdevice->base.me_subdevice_io_reset_subdevice =
 801            me8200_di_io_reset_subdevice;
 802        subdevice->base.me_subdevice_io_single_config =
 803            me8200_di_io_single_config;
 804        subdevice->base.me_subdevice_io_single_read = me8200_di_io_single_read;
 805        subdevice->base.me_subdevice_query_number_channels =
 806            me8200_di_query_number_channels;
 807        subdevice->base.me_subdevice_query_subdevice_type =
 808            me8200_di_query_subdevice_type;
 809        subdevice->base.me_subdevice_query_subdevice_caps =
 810            me8200_di_query_subdevice_caps;
 811        subdevice->base.me_subdevice_destructor = me8200_di_destructor;
 812
 813        subdevice->rised = 0;
 814        subdevice->count = 0;
 815
 816        /* Register interrupt service routine. */
 817        subdevice->irq = irq;
 818        if (subdevice->version > 0) {   // NEW
 819                err = request_irq(subdevice->irq, me8200_isr_EX,
 820#ifdef IRQF_DISABLED
 821                                  IRQF_DISABLED | IRQF_SHARED,
 822#else
 823                                  SA_INTERRUPT | SA_SHIRQ,
 824#endif
 825                                  ME8200_NAME, (void *)subdevice);
 826        } else {                //OLD
 827                err = request_irq(subdevice->irq, me8200_isr,
 828#ifdef IRQF_DISABLED
 829                                  IRQF_DISABLED | IRQF_SHARED,
 830#else
 831                                  SA_INTERRUPT | SA_SHIRQ,
 832#endif
 833                                  ME8200_NAME, (void *)subdevice);
 834        }
 835
 836        if (err) {
 837                PERROR("Cannot initialize subdevice base class instance.\n");
 838                kfree(subdevice);
 839                return NULL;
 840        }
 841        PDEBUG("Registred irq=%d.\n", subdevice->irq);
 842
 843        return subdevice;
 844}
 845
 846static void me8200_di_check_version(me8200_di_subdevice_t * instance,
 847                                    unsigned long addr)
 848{
 849
 850        PDEBUG("executed.\n");
 851        instance->version = 0x000000FF & inb(addr);
 852        PDEVELOP("me8200 firmware version: %d\n", instance->version);
 853
 854        /// @note Fix for wrong values in this registry.
 855        if ((instance->version < 0x7) || (instance->version > 0x1F))
 856                instance->version = 0x0;
 857}
 858
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.