linux/drivers/staging/meilhaus/me0600_relay.c
<<
>>
Prefs
   1/**
   2 * @file me0600_relay.c
   3 *
   4 * @brief ME-630 relay 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/module.h>
  36
  37#include <linux/slab.h>
  38#include <linux/spinlock.h>
  39#include <asm/io.h>
  40#include <linux/types.h>
  41
  42#include "medefines.h"
  43#include "meinternal.h"
  44#include "meerror.h"
  45
  46#include "medebug.h"
  47#include "me0600_relay_reg.h"
  48#include "me0600_relay.h"
  49
  50/*
  51 * Defines
  52 */
  53
  54/*
  55 * Functions
  56 */
  57
  58static int me0600_relay_io_reset_subdevice(struct me_subdevice *subdevice,
  59                                           struct file *filep, int flags)
  60{
  61        me0600_relay_subdevice_t *instance;
  62
  63        PDEBUG("executed.\n");
  64
  65        instance = (me0600_relay_subdevice_t *) subdevice;
  66
  67        if (flags) {
  68                PERROR("Invalid flag specified.\n");
  69                return ME_ERRNO_INVALID_FLAGS;
  70        }
  71
  72        ME_SUBDEVICE_ENTER;
  73
  74        spin_lock(&instance->subdevice_lock);
  75        outb(0x0, instance->port_0_reg);
  76        PDEBUG_REG("port_0_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
  77                   instance->port_0_reg - instance->reg_base, 0);
  78        outb(0x0, instance->port_1_reg);
  79        PDEBUG_REG("port_1_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
  80                   instance->port_1_reg - instance->reg_base, 0);
  81        spin_unlock(&instance->subdevice_lock);
  82
  83        ME_SUBDEVICE_EXIT;
  84
  85        return ME_ERRNO_SUCCESS;
  86}
  87
  88static int me0600_relay_io_single_config(me_subdevice_t * subdevice,
  89                                         struct file *filep,
  90                                         int channel,
  91                                         int single_config,
  92                                         int ref,
  93                                         int trig_chan,
  94                                         int trig_type,
  95                                         int trig_edge, int flags)
  96{
  97        me0600_relay_subdevice_t *instance;
  98        int err = ME_ERRNO_SUCCESS;
  99
 100        PDEBUG("executed.\n");
 101
 102        instance = (me0600_relay_subdevice_t *) subdevice;
 103
 104        ME_SUBDEVICE_ENTER;
 105
 106        spin_lock(&instance->subdevice_lock);
 107
 108        switch (flags) {
 109        case ME_IO_SINGLE_CONFIG_NO_FLAGS:
 110        case ME_IO_SINGLE_CONFIG_DIO_WORD:
 111                if (channel == 0) {
 112                        if (single_config != ME_SINGLE_CONFIG_DIO_OUTPUT) {
 113                                PERROR("Invalid word direction specified.\n");
 114                                err = ME_ERRNO_INVALID_SINGLE_CONFIG;
 115                        }
 116                } else {
 117                        PERROR("Invalid channel specified.\n");
 118                        err = ME_ERRNO_INVALID_CHANNEL;
 119                }
 120
 121                break;
 122
 123        default:
 124                PERROR("Invalid flags specified.\n");
 125
 126                err = ME_ERRNO_INVALID_FLAGS;
 127
 128                break;
 129        }
 130
 131        spin_unlock(&instance->subdevice_lock);
 132
 133        ME_SUBDEVICE_EXIT;
 134
 135        return err;
 136}
 137
 138static int me0600_relay_io_single_read(me_subdevice_t * subdevice,
 139                                       struct file *filep,
 140                                       int channel,
 141                                       int *value, int time_out, int flags)
 142{
 143        me0600_relay_subdevice_t *instance;
 144        int err = ME_ERRNO_SUCCESS;
 145
 146        PDEBUG("executed.\n");
 147
 148        instance = (me0600_relay_subdevice_t *) subdevice;
 149
 150        ME_SUBDEVICE_ENTER;
 151
 152        spin_lock(&instance->subdevice_lock);
 153
 154        switch (flags) {
 155
 156        case ME_IO_SINGLE_TYPE_DIO_BIT:
 157                if ((channel >= 0) && (channel < 8)) {
 158                        *value = inb(instance->port_0_reg) & (0x1 << channel);
 159                } else if ((channel >= 8) && (channel < 16)) {
 160                        *value =
 161                            inb(instance->port_1_reg) & (0x1 << (channel - 8));
 162                } else {
 163                        PERROR("Invalid bit number specified.\n");
 164                        err = ME_ERRNO_INVALID_CHANNEL;
 165                }
 166
 167                break;
 168
 169        case ME_IO_SINGLE_TYPE_DIO_BYTE:
 170                if (channel == 0) {
 171                        *value = inb(instance->port_0_reg);
 172                } else if (channel == 1) {
 173                        *value = inb(instance->port_1_reg);
 174                } else {
 175                        PERROR("Invalid byte number specified.\n");
 176                        err = ME_ERRNO_INVALID_CHANNEL;
 177                }
 178
 179                break;
 180
 181        case ME_IO_SINGLE_NO_FLAGS:
 182        case ME_IO_SINGLE_TYPE_DIO_WORD:
 183                if (channel == 0) {
 184                        *value = (uint32_t) inb(instance->port_1_reg) << 8;
 185                        *value |= inb(instance->port_0_reg);
 186                } else {
 187                        PERROR("Invalid word number specified.\n");
 188                        err = ME_ERRNO_INVALID_CHANNEL;
 189                }
 190
 191                break;
 192
 193        default:
 194                PERROR("Invalid flags specified.\n");
 195
 196                err = ME_ERRNO_INVALID_FLAGS;
 197        }
 198
 199        spin_unlock(&instance->subdevice_lock);
 200
 201        ME_SUBDEVICE_EXIT;
 202
 203        return err;
 204}
 205
 206static int me0600_relay_io_single_write(me_subdevice_t * subdevice,
 207                                        struct file *filep,
 208                                        int channel,
 209                                        int value, int time_out, int flags)
 210{
 211        me0600_relay_subdevice_t *instance;
 212        int err = ME_ERRNO_SUCCESS;
 213        uint8_t state;
 214
 215        PDEBUG("executed.\n");
 216
 217        instance = (me0600_relay_subdevice_t *) subdevice;
 218
 219        ME_SUBDEVICE_ENTER;
 220
 221        spin_lock(&instance->subdevice_lock);
 222
 223        switch (flags) {
 224        case ME_IO_SINGLE_TYPE_DIO_BIT:
 225                if ((channel >= 0) && (channel < 8)) {
 226                        state = inb(instance->port_0_reg);
 227                        state =
 228                            value ? (state | (0x1 << channel)) : (state &
 229                                                                  ~(0x1 <<
 230                                                                    channel));
 231                        outb(state, instance->port_0_reg);
 232                } else if ((channel >= 8) && (channel < 16)) {
 233                        state = inb(instance->port_1_reg);
 234                        state =
 235                            value ? (state | (0x1 << (channel - 8))) : (state &
 236                                                                        ~(0x1 <<
 237                                                                          (channel
 238                                                                           -
 239                                                                           8)));
 240                        outb(state, instance->port_1_reg);
 241                } else {
 242                        PERROR("Invalid bit number specified.\n");
 243                        err = ME_ERRNO_INVALID_CHANNEL;
 244                }
 245                break;
 246
 247        case ME_IO_SINGLE_TYPE_DIO_BYTE:
 248                if (channel == 0) {
 249                        outb(value, instance->port_0_reg);
 250                } else if (channel == 1) {
 251                        outb(value, instance->port_1_reg);
 252                } else {
 253                        PERROR("Invalid byte number specified.\n");
 254                        err = ME_ERRNO_INVALID_CHANNEL;
 255                }
 256                break;
 257
 258        case ME_IO_SINGLE_NO_FLAGS:
 259        case ME_IO_SINGLE_TYPE_DIO_WORD:
 260                if (channel == 0) {
 261                        outb(value, instance->port_0_reg);
 262                        outb(value >> 8, instance->port_1_reg);
 263                } else {
 264                        PERROR("Invalid word number specified.\n");
 265                        err = ME_ERRNO_INVALID_CHANNEL;
 266                }
 267                break;
 268
 269        default:
 270                PERROR("Invalid flags specified.\n");
 271                err = ME_ERRNO_INVALID_FLAGS;
 272                break;
 273        }
 274
 275        spin_unlock(&instance->subdevice_lock);
 276
 277        ME_SUBDEVICE_EXIT;
 278
 279        return err;
 280}
 281
 282static int me0600_relay_query_number_channels(me_subdevice_t * subdevice,
 283                                              int *number)
 284{
 285        PDEBUG("executed.\n");
 286        *number = 16;
 287        return ME_ERRNO_SUCCESS;
 288}
 289
 290static int me0600_relay_query_subdevice_type(me_subdevice_t * subdevice,
 291                                             int *type, int *subtype)
 292{
 293        PDEBUG("executed.\n");
 294        *type = ME_TYPE_DO;
 295        *subtype = ME_SUBTYPE_SINGLE;
 296        return ME_ERRNO_SUCCESS;
 297}
 298
 299static int me0600_relay_query_subdevice_caps(me_subdevice_t * subdevice,
 300                                             int *caps)
 301{
 302        PDEBUG("executed.\n");
 303        *caps = 0;
 304        return ME_ERRNO_SUCCESS;
 305}
 306
 307me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base)
 308{
 309        me0600_relay_subdevice_t *subdevice;
 310        int err;
 311
 312        PDEBUG("executed.\n");
 313
 314        /* Allocate memory for subdevice instance */
 315        subdevice = kmalloc(sizeof(me0600_relay_subdevice_t), GFP_KERNEL);
 316
 317        if (!subdevice) {
 318                PERROR("Cannot get memory for subdevice instance.\n");
 319                return NULL;
 320        }
 321
 322        memset(subdevice, 0, sizeof(me0600_relay_subdevice_t));
 323
 324        /* Initialize subdevice base class */
 325        err = me_subdevice_init(&subdevice->base);
 326
 327        if (err) {
 328                PERROR("Cannot initialize subdevice base class instance.\n");
 329                kfree(subdevice);
 330                return NULL;
 331        }
 332        // Initialize spin locks.
 333        spin_lock_init(&subdevice->subdevice_lock);
 334
 335        /* Save the subdevice index */
 336        subdevice->port_0_reg = reg_base + ME0600_RELAIS_0_REG;
 337        subdevice->port_1_reg = reg_base + ME0600_RELAIS_1_REG;
 338#ifdef MEDEBUG_DEBUG_REG
 339        subdevice->reg_base = reg_base;
 340#endif
 341
 342        /* Overload base class methods. */
 343        subdevice->base.me_subdevice_io_reset_subdevice =
 344            me0600_relay_io_reset_subdevice;
 345        subdevice->base.me_subdevice_io_single_config =
 346            me0600_relay_io_single_config;
 347        subdevice->base.me_subdevice_io_single_read =
 348            me0600_relay_io_single_read;
 349        subdevice->base.me_subdevice_io_single_write =
 350            me0600_relay_io_single_write;
 351        subdevice->base.me_subdevice_query_number_channels =
 352            me0600_relay_query_number_channels;
 353        subdevice->base.me_subdevice_query_subdevice_type =
 354            me0600_relay_query_subdevice_type;
 355        subdevice->base.me_subdevice_query_subdevice_caps =
 356            me0600_relay_query_subdevice_caps;
 357
 358        return subdevice;
 359}
 360
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.