linux/drivers/staging/meilhaus/me1600_device.c
<<
>>
Prefs
   1/**
   2 * @file me1600_device.c
   3 *
   4 * @brief ME-1600 device class implementation.
   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#ifndef MODULE
  33#  define MODULE
  34#endif
  35
  36#include <linux/module.h>
  37
  38#include <linux/pci.h>
  39#include <linux/slab.h>
  40
  41#include "meids.h"
  42#include "meerror.h"
  43#include "mecommon.h"
  44#include "meinternal.h"
  45
  46#include "medebug.h"
  47#include "medevice.h"
  48#include "mesubdevice.h"
  49#include "me1600_device.h"
  50
  51static void me1600_set_registry(me1600_device_t * subdevice, uint32_t reg_base);
  52static void me1600_destructor(struct me_device *device);
  53
  54/**
  55 * @brief Global variable.
  56 * This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts).
  57 */
  58static struct workqueue_struct *me1600_workqueue;
  59
  60me_device_t *me1600_pci_constructor(struct pci_dev *pci_device)
  61{
  62        int err;
  63        me1600_device_t *me1600_device;
  64        me_subdevice_t *subdevice;
  65        unsigned int chip_idx;
  66        int i;
  67
  68        PDEBUG("executed.\n");
  69
  70        // Allocate structure for device instance.
  71        me1600_device = kmalloc(sizeof(me1600_device_t), GFP_KERNEL);
  72
  73        if (!me1600_device) {
  74                PERROR("Cannot get memory for device instance.\n");
  75                return NULL;
  76        }
  77
  78        memset(me1600_device, 0, sizeof(me1600_device_t));
  79
  80        // Initialize base class structure.
  81        err = me_device_pci_init((me_device_t *) me1600_device, pci_device);
  82
  83        if (err) {
  84                kfree(me1600_device);
  85                PERROR("Cannot initialize device base class.\n");
  86                return NULL;
  87        }
  88        // Initialize spin lock .
  89        spin_lock_init(&me1600_device->config_regs_lock);
  90        spin_lock_init(&me1600_device->ao_shadows_lock);
  91
  92        // Get the number of analog output subdevices.
  93        chip_idx =
  94            me1600_versions_get_device_index(me1600_device->base.info.pci.
  95                                             device_id);
  96
  97        // Create shadow instance.
  98        me1600_device->ao_regs_shadows.count =
  99            me1600_versions[chip_idx].ao_chips;
 100        me1600_device->ao_regs_shadows.registry =
 101            kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(unsigned long),
 102                    GFP_KERNEL);
 103        me1600_set_registry(me1600_device,
 104                            me1600_device->base.info.pci.reg_bases[2]);
 105        me1600_device->ao_regs_shadows.shadow =
 106            kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t),
 107                    GFP_KERNEL);
 108        me1600_device->ao_regs_shadows.mirror =
 109            kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t),
 110                    GFP_KERNEL);
 111
 112        // Create subdevice instances.
 113        for (i = 0; i < me1600_versions[chip_idx].ao_chips; i++) {
 114                subdevice =
 115                    (me_subdevice_t *) me1600_ao_constructor(me1600_device->
 116                                                             base.info.pci.
 117                                                             reg_bases[2], i,
 118                                                             ((me1600_versions
 119                                                               [chip_idx].curr >
 120                                                               i) ? 1 : 0),
 121                                                             &me1600_device->
 122                                                             config_regs_lock,
 123                                                             &me1600_device->
 124                                                             ao_shadows_lock,
 125                                                             &me1600_device->
 126                                                             ao_regs_shadows,
 127                                                             me1600_workqueue);
 128
 129                if (!subdevice) {
 130                        me_device_deinit((me_device_t *) me1600_device);
 131                        kfree(me1600_device);
 132                        PERROR("Cannot get memory for subdevice.\n");
 133                        return NULL;
 134                }
 135
 136                me_slist_add_subdevice_tail(&me1600_device->base.slist,
 137                                            subdevice);
 138        }
 139
 140        // Overwrite base class methods.
 141        me1600_device->base.me_device_destructor = me1600_destructor;
 142
 143        return (me_device_t *) me1600_device;
 144}
 145
 146static void me1600_destructor(struct me_device *device)
 147{
 148        me1600_device_t *me1600_device = (me1600_device_t *) device;
 149        PDEBUG("executed.\n");
 150
 151        // Destroy shadow instance.
 152        kfree(me1600_device->ao_regs_shadows.registry);
 153        kfree(me1600_device->ao_regs_shadows.shadow);
 154        kfree(me1600_device->ao_regs_shadows.mirror);
 155
 156        me_device_deinit((me_device_t *) me1600_device);
 157        kfree(me1600_device);
 158}
 159
 160static void me1600_set_registry(me1600_device_t * subdevice, uint32_t reg_base)
 161{                               // Create shadow structure.
 162        if (subdevice->ao_regs_shadows.count >= 1) {
 163                subdevice->ao_regs_shadows.registry[0] =
 164                    (unsigned long)(reg_base + ME1600_CHANNEL_0_REG);
 165        }
 166        if (subdevice->ao_regs_shadows.count >= 2) {
 167                subdevice->ao_regs_shadows.registry[1] =
 168                    (unsigned long)(reg_base + ME1600_CHANNEL_1_REG);
 169        }
 170        if (subdevice->ao_regs_shadows.count >= 3) {
 171                subdevice->ao_regs_shadows.registry[2] =
 172                    (unsigned long)(reg_base + ME1600_CHANNEL_2_REG);
 173        }
 174        if (subdevice->ao_regs_shadows.count >= 4) {
 175                subdevice->ao_regs_shadows.registry[3] =
 176                    (unsigned long)(reg_base + ME1600_CHANNEL_3_REG);
 177        }
 178        if (subdevice->ao_regs_shadows.count >= 5) {
 179                subdevice->ao_regs_shadows.registry[4] =
 180                    (unsigned long)(reg_base + ME1600_CHANNEL_4_REG);
 181        }
 182        if (subdevice->ao_regs_shadows.count >= 6) {
 183                subdevice->ao_regs_shadows.registry[5] =
 184                    (unsigned long)(reg_base + ME1600_CHANNEL_5_REG);
 185        }
 186        if (subdevice->ao_regs_shadows.count >= 7) {
 187                subdevice->ao_regs_shadows.registry[6] =
 188                    (unsigned long)(reg_base + ME1600_CHANNEL_6_REG);
 189        }
 190        if (subdevice->ao_regs_shadows.count >= 8) {
 191                subdevice->ao_regs_shadows.registry[7] =
 192                    (unsigned long)(reg_base + ME1600_CHANNEL_7_REG);
 193        }
 194        if (subdevice->ao_regs_shadows.count >= 9) {
 195                subdevice->ao_regs_shadows.registry[8] =
 196                    (unsigned long)(reg_base + ME1600_CHANNEL_8_REG);
 197        }
 198        if (subdevice->ao_regs_shadows.count >= 10) {
 199                subdevice->ao_regs_shadows.registry[9] =
 200                    (unsigned long)(reg_base + ME1600_CHANNEL_9_REG);
 201        }
 202        if (subdevice->ao_regs_shadows.count >= 11) {
 203                subdevice->ao_regs_shadows.registry[10] =
 204                    (unsigned long)(reg_base + ME1600_CHANNEL_10_REG);
 205        }
 206        if (subdevice->ao_regs_shadows.count >= 12) {
 207                subdevice->ao_regs_shadows.registry[11] =
 208                    (unsigned long)(reg_base + ME1600_CHANNEL_11_REG);
 209        }
 210        if (subdevice->ao_regs_shadows.count >= 13) {
 211                subdevice->ao_regs_shadows.registry[12] =
 212                    (unsigned long)(reg_base + ME1600_CHANNEL_12_REG);
 213        }
 214        if (subdevice->ao_regs_shadows.count >= 14) {
 215                subdevice->ao_regs_shadows.registry[13] =
 216                    (unsigned long)(reg_base + ME1600_CHANNEL_13_REG);
 217        }
 218        if (subdevice->ao_regs_shadows.count >= 15) {
 219                subdevice->ao_regs_shadows.registry[14] =
 220                    (unsigned long)(reg_base + ME1600_CHANNEL_14_REG);
 221        }
 222        if (subdevice->ao_regs_shadows.count >= 16) {
 223                subdevice->ao_regs_shadows.registry[15] =
 224                    (unsigned long)(reg_base + ME1600_CHANNEL_15_REG);
 225        }
 226        if (subdevice->ao_regs_shadows.count > 16) {
 227                PERROR("More than 16 outputs! (%d)\n",
 228                       subdevice->ao_regs_shadows.count);
 229        }
 230}
 231
 232// Init and exit of module.
 233
 234static int __init me1600_init(void)
 235{
 236        PDEBUG("executed\n.");
 237
 238        me1600_workqueue = create_singlethread_workqueue("me1600");
 239        return 0;
 240}
 241
 242static void __exit me1600_exit(void)
 243{
 244        PDEBUG("executed\n.");
 245
 246        flush_workqueue(me1600_workqueue);
 247        destroy_workqueue(me1600_workqueue);
 248}
 249
 250module_init(me1600_init);
 251module_exit(me1600_exit);
 252
 253// Administrative stuff for modinfo.
 254MODULE_AUTHOR
 255    ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>");
 256MODULE_DESCRIPTION("Device Driver Module for ME-1600 Device");
 257MODULE_SUPPORTED_DEVICE("Meilhaus ME-1600 Devices");
 258MODULE_LICENSE("GPL");
 259
 260// Export the constructor.
 261EXPORT_SYMBOL(me1600_pci_constructor);
 262
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.