linux/drivers/staging/meilhaus/me8255.c
<<
>>
Prefs
   1/**
   2 * @file me8255.c
   3 *
   4 * @brief 8255 subdevice instance.
   5 * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
   6 * @author Guenter Gebhardt
   7 */
   8
   9/*
  10 * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
  11 *
  12 * This file is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25 */
  26
  27#ifndef __KERNEL__
  28#  define __KERNEL__
  29#endif
  30
  31/*
  32 * Includes
  33 */
  34#include <linux/module.h>
  35
  36#include <linux/slab.h>
  37#include <linux/spinlock.h>
  38#include <asm/io.h>
  39#include <linux/types.h>
  40
  41#include "medefines.h"
  42#include "meinternal.h"
  43#include "meerror.h"
  44#include "medebug.h"
  45
  46#include "me8255_reg.h"
  47#include "me8255.h"
  48
  49/*
  50 * Defines
  51 */
  52
  53/*
  54 * Functions
  55 */
  56
  57static uint8_t get_mode_from_mirror(uint32_t mirror)
  58{
  59        PDEBUG("executed.\n");
  60
  61        if (mirror & ME8255_PORT_0_OUTPUT) {
  62                if (mirror & ME8255_PORT_1_OUTPUT) {
  63                        if (mirror & ME8255_PORT_2_OUTPUT) {
  64                                return ME8255_MODE_OOO;
  65                        } else {
  66                                return ME8255_MODE_IOO;
  67                        }
  68                } else {
  69                        if (mirror & ME8255_PORT_2_OUTPUT) {
  70                                return ME8255_MODE_OIO;
  71                        } else {
  72                                return ME8255_MODE_IIO;
  73                        }
  74                }
  75        } else {
  76                if (mirror & ME8255_PORT_1_OUTPUT) {
  77                        if (mirror & ME8255_PORT_2_OUTPUT) {
  78                                return ME8255_MODE_OOI;
  79                        } else {
  80                                return ME8255_MODE_IOI;
  81                        }
  82                } else {
  83                        if (mirror & ME8255_PORT_2_OUTPUT) {
  84                                return ME8255_MODE_OII;
  85                        } else {
  86                                return ME8255_MODE_III;
  87                        }
  88                }
  89        }
  90}
  91
  92static int me8255_io_reset_subdevice(struct me_subdevice *subdevice,
  93                                     struct file *filep, int flags)
  94{
  95        me8255_subdevice_t *instance;
  96
  97        PDEBUG("executed.\n");
  98
  99        instance = (me8255_subdevice_t *) subdevice;
 100
 101        if (flags) {
 102                PERROR("Invalid flag specified.\n");
 103                return ME_ERRNO_INVALID_FLAGS;
 104        }
 105
 106        ME_SUBDEVICE_ENTER;
 107
 108        spin_lock(&instance->subdevice_lock);
 109        spin_lock(instance->ctrl_reg_lock);
 110        *instance->ctrl_reg_mirror &=
 111            ~(ME8255_PORT_0_OUTPUT << instance->dio_idx);
 112        outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
 113             instance->ctrl_reg);
 114        spin_unlock(instance->ctrl_reg_lock);
 115
 116        outb(0, instance->port_reg);
 117        spin_unlock(&instance->subdevice_lock);
 118
 119        ME_SUBDEVICE_EXIT;
 120
 121        return ME_ERRNO_SUCCESS;
 122}
 123
 124static int me8255_io_single_config(struct me_subdevice *subdevice,
 125                                   struct file *filep,
 126                                   int channel,
 127                                   int single_config,
 128                                   int ref,
 129                                   int trig_chan,
 130                                   int trig_type, int trig_edge, int flags)
 131{
 132        me8255_subdevice_t *instance;
 133        int err = ME_ERRNO_SUCCESS;
 134
 135        PDEBUG("executed.\n");
 136
 137        instance = (me8255_subdevice_t *) subdevice;
 138
 139        if (flags & ~ME_IO_SINGLE_CONFIG_DIO_BYTE) {
 140                PERROR("Invalid flag specified.\n");
 141                return ME_ERRNO_INVALID_FLAGS;
 142        }
 143
 144        if (channel) {
 145                PERROR("Invalid channel.\n");
 146                return ME_ERRNO_INVALID_CHANNEL;
 147        }
 148
 149        ME_SUBDEVICE_ENTER;
 150
 151        spin_lock(&instance->subdevice_lock);
 152        if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
 153                spin_lock(instance->ctrl_reg_lock);
 154                *instance->ctrl_reg_mirror &=
 155                    ~(ME8255_PORT_0_OUTPUT << instance->dio_idx);
 156                outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
 157                     instance->ctrl_reg);
 158                spin_unlock(instance->ctrl_reg_lock);
 159        } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
 160                spin_lock(instance->ctrl_reg_lock);
 161                *instance->ctrl_reg_mirror |=
 162                    (ME8255_PORT_0_OUTPUT << instance->dio_idx);
 163                outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
 164                     instance->ctrl_reg);
 165                spin_unlock(instance->ctrl_reg_lock);
 166        } else {
 167                PERROR("Invalid port direction.\n");
 168                err = ME_ERRNO_INVALID_SINGLE_CONFIG;
 169        }
 170        spin_unlock(&instance->subdevice_lock);
 171
 172        ME_SUBDEVICE_EXIT;
 173
 174        return err;
 175}
 176
 177static int me8255_io_single_read(struct me_subdevice *subdevice,
 178                                 struct file *filep,
 179                                 int channel,
 180                                 int *value, int time_out, int flags)
 181{
 182        me8255_subdevice_t *instance;
 183        int err = ME_ERRNO_SUCCESS;
 184
 185        PDEBUG("executed.\n");
 186
 187        instance = (me8255_subdevice_t *) subdevice;
 188
 189        ME_SUBDEVICE_ENTER;
 190
 191        spin_lock(&instance->subdevice_lock);
 192        switch (flags) {
 193        case ME_IO_SINGLE_TYPE_DIO_BIT:
 194                if ((channel >= 0) && (channel < 8)) {
 195                        *value = inb(instance->port_reg) & (0x1 << channel);
 196                } else {
 197                        PERROR("Invalid bit number.\n");
 198                        err = ME_ERRNO_INVALID_CHANNEL;
 199                }
 200                break;
 201
 202        case ME_IO_SINGLE_NO_FLAGS:
 203        case ME_IO_SINGLE_TYPE_DIO_BYTE:
 204                if (channel == 0) {
 205                        *value = inb(instance->port_reg);
 206                } else {
 207                        PERROR("Invalid byte number.\n");
 208                        err = ME_ERRNO_INVALID_CHANNEL;
 209                }
 210                break;
 211
 212        default:
 213                PERROR("Invalid flags specified.\n");
 214                err = ME_ERRNO_INVALID_FLAGS;
 215        }
 216        spin_unlock(&instance->subdevice_lock);
 217
 218        ME_SUBDEVICE_EXIT;
 219
 220        return err;
 221}
 222
 223static int me8255_io_single_write(struct me_subdevice *subdevice,
 224                                  struct file *filep,
 225                                  int channel,
 226                                  int value, int time_out, int flags)
 227{
 228        me8255_subdevice_t *instance;
 229        uint8_t byte;
 230        int err = ME_ERRNO_SUCCESS;
 231
 232        PDEBUG("executed.\n");
 233
 234        instance = (me8255_subdevice_t *) subdevice;
 235
 236        ME_SUBDEVICE_ENTER;
 237
 238        spin_lock(&instance->subdevice_lock);
 239        switch (flags) {
 240        case ME_IO_SINGLE_TYPE_DIO_BIT:
 241                if ((channel >= 0) && (channel < 8)) {
 242                        if (*instance->
 243                            ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT <<
 244                                               instance->dio_idx)) {
 245                                byte = inb(instance->port_reg);
 246
 247                                if (value)
 248                                        byte |= 0x1 << channel;
 249                                else
 250                                        byte &= ~(0x1 << channel);
 251
 252                                outb(byte, instance->port_reg);
 253                        } else {
 254                                PERROR("Port not in output mode.\n");
 255                                err = ME_ERRNO_PREVIOUS_CONFIG;
 256                        }
 257                } else {
 258                        PERROR("Invalid bit number.\n");
 259                        err = ME_ERRNO_INVALID_CHANNEL;
 260                }
 261                break;
 262
 263        case ME_IO_SINGLE_NO_FLAGS:
 264        case ME_IO_SINGLE_TYPE_DIO_BYTE:
 265                if (channel == 0) {
 266                        if (*instance->
 267                            ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT <<
 268                                               instance->dio_idx)) {
 269                                outb(value, instance->port_reg);
 270                        } else {
 271                                PERROR("Port not in output mode.\n");
 272                                err = ME_ERRNO_PREVIOUS_CONFIG;
 273                        }
 274                } else {
 275                        PERROR("Invalid byte number.\n");
 276                        err = ME_ERRNO_INVALID_CHANNEL;
 277                }
 278                break;
 279
 280        default:
 281                PERROR("Invalid flags specified.\n");
 282                err = ME_ERRNO_INVALID_FLAGS;
 283        }
 284        spin_unlock(&instance->subdevice_lock);
 285
 286        ME_SUBDEVICE_EXIT;
 287
 288        return err;
 289}
 290
 291static int me8255_query_number_channels(struct me_subdevice *subdevice,
 292                                        int *number)
 293{
 294        PDEBUG("executed.\n");
 295        *number = ME8255_NUMBER_CHANNELS;
 296        return ME_ERRNO_SUCCESS;
 297}
 298
 299static int me8255_query_subdevice_type(struct me_subdevice *subdevice,
 300                                       int *type, int *subtype)
 301{
 302        PDEBUG("executed.\n");
 303        *type = ME_TYPE_DIO;
 304        *subtype = ME_SUBTYPE_SINGLE;
 305        return ME_ERRNO_SUCCESS;
 306}
 307
 308static int me8255_query_subdevice_caps(struct me_subdevice *subdevice,
 309                                       int *caps)
 310{
 311        PDEBUG("executed.\n");
 312        *caps = ME_CAPS_DIO_DIR_BYTE;
 313        return ME_ERRNO_SUCCESS;
 314}
 315
 316me8255_subdevice_t *me8255_constructor(uint32_t device_id,
 317                                       uint32_t reg_base,
 318                                       unsigned int me8255_idx,
 319                                       unsigned int dio_idx,
 320                                       int *ctrl_reg_mirror,
 321                                       spinlock_t * ctrl_reg_lock)
 322{
 323        me8255_subdevice_t *subdevice;
 324        int err;
 325
 326        PDEBUG("executed.\n");
 327
 328        /* Allocate memory for subdevice instance */
 329        subdevice = kmalloc(sizeof(me8255_subdevice_t), GFP_KERNEL);
 330
 331        if (!subdevice) {
 332                PERROR("Cannot get memory for 8255 instance.\n");
 333                return NULL;
 334        }
 335
 336        memset(subdevice, 0, sizeof(me8255_subdevice_t));
 337
 338        /* Check if counter index is out of range */
 339
 340        if (dio_idx > 2) {
 341                PERROR("DIO index is out of range.\n");
 342                kfree(subdevice);
 343                return NULL;
 344        }
 345
 346        /* Initialize subdevice base class */
 347        err = me_subdevice_init(&subdevice->base);
 348
 349        if (err) {
 350                PERROR("Cannot initialize subdevice base class instance.\n");
 351                kfree(subdevice);
 352                return NULL;
 353        }
 354        // Initialize spin locks.
 355        spin_lock_init(&subdevice->subdevice_lock);
 356
 357        subdevice->ctrl_reg_lock = ctrl_reg_lock;
 358
 359        /* Save the pointer to global port settings */
 360        subdevice->ctrl_reg_mirror = ctrl_reg_mirror;
 361
 362        /* Save type of Meilhaus device */
 363        subdevice->device_id = device_id;
 364
 365        /* Save the indices */
 366        subdevice->me8255_idx = me8255_idx;
 367        subdevice->dio_idx = dio_idx;
 368
 369        /* Do device specific initialization */
 370        switch (device_id) {
 371        case PCI_DEVICE_ID_MEILHAUS_ME1400:
 372        case PCI_DEVICE_ID_MEILHAUS_ME14E0:
 373
 374        case PCI_DEVICE_ID_MEILHAUS_ME140A:
 375        case PCI_DEVICE_ID_MEILHAUS_ME14EA:
 376                /* Check if 8255 index is out of range */
 377                if (me8255_idx > 0) {
 378                        PERROR("8255 index is out of range.\n");
 379                        me_subdevice_deinit(&subdevice->base);
 380                        kfree(subdevice);
 381                        return NULL;
 382                }
 383
 384        case PCI_DEVICE_ID_MEILHAUS_ME140B:     /* Fall through */
 385        case PCI_DEVICE_ID_MEILHAUS_ME14EB:
 386                /* Check if 8255 index is out of range */
 387                if (me8255_idx > 1) {
 388                        PERROR("8255 index is out of range.\n");
 389                        me_subdevice_deinit(&subdevice->base);
 390                        kfree(subdevice);
 391                        return NULL;
 392                }
 393
 394                /* Get the registers */
 395                if (me8255_idx == 0) {
 396                        subdevice->ctrl_reg = reg_base + ME1400AB_PORT_A_CTRL;
 397                        subdevice->port_reg =
 398                            reg_base + ME1400AB_PORT_A_0 + dio_idx;
 399                } else if (me8255_idx == 1) {
 400                        subdevice->ctrl_reg = reg_base + ME1400AB_PORT_B_CTRL;
 401                        subdevice->port_reg =
 402                            reg_base + ME1400AB_PORT_B_0 + dio_idx;
 403                }
 404
 405                break;
 406
 407        case PCI_DEVICE_ID_MEILHAUS_ME140C:
 408                /* Check if 8255 index is out of range */
 409                if (me8255_idx > 0) {
 410                        PERROR("8255 index is out of range.\n");
 411                        me_subdevice_deinit(&subdevice->base);
 412                        kfree(subdevice);
 413                        return NULL;
 414                }
 415
 416        case PCI_DEVICE_ID_MEILHAUS_ME140D:     /* Fall through */
 417                /* Check if 8255 index is out of range */
 418                if (me8255_idx > 1) {
 419                        PERROR("8255 index is out of range.\n");
 420                        me_subdevice_deinit(&subdevice->base);
 421                        kfree(subdevice);
 422                        return NULL;
 423                }
 424
 425                /* Get the registers */
 426                if (me8255_idx == 0) {
 427                        subdevice->ctrl_reg = reg_base + ME1400CD_PORT_A_CTRL;
 428                        subdevice->port_reg =
 429                            reg_base + ME1400CD_PORT_A_0 + dio_idx;
 430                } else if (me8255_idx == 1) {
 431                        subdevice->ctrl_reg = reg_base + ME1400CD_PORT_B_CTRL;
 432                        subdevice->port_reg =
 433                            reg_base + ME1400CD_PORT_B_0 + dio_idx;
 434                }
 435
 436                break;
 437
 438        default:
 439                PERROR("Unknown device type. dev ID: 0x%04x\n", device_id);
 440
 441                me_subdevice_deinit(&subdevice->base);
 442
 443                kfree(subdevice);
 444
 445                return NULL;
 446        }
 447
 448        /* Overload subdevice base class methods. */
 449        subdevice->base.me_subdevice_io_reset_subdevice =
 450            me8255_io_reset_subdevice;
 451        subdevice->base.me_subdevice_io_single_config = me8255_io_single_config;
 452        subdevice->base.me_subdevice_io_single_read = me8255_io_single_read;
 453        subdevice->base.me_subdevice_io_single_write = me8255_io_single_write;
 454        subdevice->base.me_subdevice_query_number_channels =
 455            me8255_query_number_channels;
 456        subdevice->base.me_subdevice_query_subdevice_type =
 457            me8255_query_subdevice_type;
 458        subdevice->base.me_subdevice_query_subdevice_caps =
 459            me8255_query_subdevice_caps;
 460
 461        return subdevice;
 462}
 463
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.