diff options
author | David Kiliani <mail@davidkiliani.de> | 2008-11-01 00:39:12 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 13:52:29 -0800 |
commit | 3fedd14818592016f7ffd84dfe134881b3896ecf (patch) | |
tree | 22574873dc7d844d4cc33d04f7e6ba03f23c639e /drivers/staging/meilhaus/memain.c | |
parent | 5ec5ec78060481e6a0cecc06ab0c6ec8b213ec80 (diff) |
Staging: Add the Meilhaus ME-IDS driver package
Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de>
and Krzysztof Gantzke <k.gantzke@meilhaus.de>
This is the drv/lnx/mod directory of ME-IDS 1.2.9 tarball with
some files from drv/lnx/include.
Signed-off-by: David Kiliani <mail@davidkiliani.de>
Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
Cc: Krzysztof Gantzke <k.gantzke@meilhaus.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/meilhaus/memain.c')
-rw-r--r-- | drivers/staging/meilhaus/memain.c | 2022 |
1 files changed, 2022 insertions, 0 deletions
diff --git a/drivers/staging/meilhaus/memain.c b/drivers/staging/meilhaus/memain.c new file mode 100644 index 00000000000..6cdeb858245 --- /dev/null +++ b/drivers/staging/meilhaus/memain.c @@ -0,0 +1,2022 @@ +/** + * @file memain.c + * + * @brief Main Meilhaus device driver. + * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) + * @author Guenter Gebhardt + * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) + */ + +/* + * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif + +#ifndef MODULE +# define MODULE +#endif + +#include <linux/module.h> +#include <linux/pci.h> +//#include <linux/usb.h> +#include <linux/errno.h> +#include <asm/uaccess.h> +#include <linux/cdev.h> +#include <linux/rwsem.h> + +#include "medefines.h" +#include "metypes.h" +#include "meerror.h" + +#include "medebug.h" +#include "memain.h" +#include "medevice.h" +#include "meioctl.h" +#include "mecommon.h" + +/* Module parameters +*/ + +#ifdef BOSCH +static unsigned int me_bosch_fw = 0; + +# ifdef module_param +module_param(me_bosch_fw, int, S_IRUGO); +# else +MODULE_PARM(me_bosch_fw, "i"); +# endif + +MODULE_PARM_DESC(me_bosch_fw, + "Flags which signals the ME-4600 driver to load the bosch firmware (default = 0)."); +#endif //BOSCH + +static unsigned int major = 0; +#ifdef module_param +module_param(major, int, S_IRUGO); +#else +MODULE_PARM(major, "i"); +#endif + +/* Global Driver Lock +*/ + +static struct file *me_filep = NULL; +static int me_count = 0; +static spinlock_t me_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_RWSEM(me_rwsem); + +/* Board instances are kept in a global list */ +LIST_HEAD(me_device_list); + +/* Prototypes +*/ + +static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id); +static void me_remove_pci(struct pci_dev *dev); +static int insert_to_device_list(me_device_t * n_device); +static int replace_with_dummy(int vendor_id, int device_id, int serial_no); +static void clear_device_list(void); +static int me_open(struct inode *inode_ptr, struct file *filep); +static int me_release(struct inode *, struct file *); +static int me_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +//static int me_probe_usb(struct usb_interface *interface, const struct usb_device_id *id); +//static void me_disconnect_usb(struct usb_interface *interface); + +/* Character device structure +*/ + +static struct cdev *cdevp; + +/* File operations provided by the module +*/ + +static struct file_operations me_file_operations = { + .owner = THIS_MODULE, + .ioctl = me_ioctl, + .open = me_open, + .release = me_release, +}; + +struct pci_driver me_pci_driver = { + .name = MEMAIN_NAME, + .id_table = me_pci_table, + .probe = me_probe_pci, + .remove = me_remove_pci +}; + +/* //me_usb_driver +static struct usb_driver me_usb_driver = +{ + .name = MEMAIN_NAME, + .id_table = me_usb_table, + .probe = me_probe_usb, + .disconnect = me_disconnect_usb +}; +*/ + +#ifdef ME_LOCK_MULTIPLEX_TEMPLATE +ME_LOCK_MULTIPLEX_TEMPLATE("me_lock_device", + me_lock_device_t, + me_lock_device, + me_device_lock_device, + (device, filep, karg.lock, karg.flags)) + + ME_LOCK_MULTIPLEX_TEMPLATE("me_lock_subdevice", + me_lock_subdevice_t, + me_lock_subdevice, + me_device_lock_subdevice, + (device, filep, karg.subdevice, karg.lock, + karg.flags)) +#else +#error macro ME_LOCK_MULTIPLEX_TEMPLATE not defined +#endif + +#ifdef ME_IO_MULTIPLEX_TEMPLATE +ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_start", + me_io_irq_start_t, + me_io_irq_start, + me_device_io_irq_start, + (device, + filep, + karg.subdevice, + karg.channel, + karg.irq_source, + karg.irq_edge, karg.irq_arg, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_wait", + me_io_irq_wait_t, + me_io_irq_wait, + me_device_io_irq_wait, + (device, + filep, + karg.subdevice, + karg.channel, + &karg.irq_count, &karg.value, karg.time_out, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_stop", + me_io_irq_stop_t, + me_io_irq_stop, + me_device_io_irq_stop, + (device, + filep, karg.subdevice, karg.channel, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_reset_device", + me_io_reset_device_t, + me_io_reset_device, + me_device_io_reset_device, (device, filep, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_reset_subdevice", + me_io_reset_subdevice_t, + me_io_reset_subdevice, + me_device_io_reset_subdevice, + (device, filep, karg.subdevice, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_single_config", + me_io_single_config_t, + me_io_single_config, + me_device_io_single_config, + (device, + filep, + karg.subdevice, + karg.channel, + karg.single_config, + karg.ref, + karg.trig_chan, + karg.trig_type, karg.trig_edge, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_new_values", + me_io_stream_new_values_t, + me_io_stream_new_values, + me_device_io_stream_new_values, + (device, + filep, + karg.subdevice, karg.time_out, &karg.count, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_read", + me_io_stream_read_t, + me_io_stream_read, + me_device_io_stream_read, + (device, + filep, + karg.subdevice, + karg.read_mode, karg.values, &karg.count, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_status", + me_io_stream_status_t, + me_io_stream_status, + me_device_io_stream_status, + (device, + filep, + karg.subdevice, + karg.wait, &karg.status, &karg.count, karg.flags)) + + ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_write", + me_io_stream_write_t, + me_io_stream_write, + me_device_io_stream_write, + (device, + filep, + karg.subdevice, + karg.write_mode, karg.values, &karg.count, karg.flags)) +#else +#error macro ME_IO_MULTIPLEX_TEMPLATE not defined +#endif + +#ifdef ME_QUERY_MULTIPLEX_STR_TEMPLATE +ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_name_device", + me_query_name_device_t, + me_query_name_device, + me_device_query_name_device, (device, &msg)) + + ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_name_device_driver", + me_query_name_device_driver_t, + me_query_name_device_driver, + me_device_query_name_device_driver, + (device, &msg)) + + ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_description_device", + me_query_description_device_t, + me_query_description_device, + me_device_query_description_device, + (device, &msg)) +#else +#error macro ME_QUERY_MULTIPLEX_STR_TEMPLATE not defined +#endif + +#ifdef ME_QUERY_MULTIPLEX_TEMPLATE +ME_QUERY_MULTIPLEX_TEMPLATE("me_query_info_device", + me_query_info_device_t, + me_query_info_device, + me_device_query_info_device, + (device, + &karg.vendor_id, + &karg.device_id, + &karg.serial_no, + &karg.bus_type, + &karg.bus_no, + &karg.dev_no, &karg.func_no, &karg.plugged)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_subdevices", + me_query_number_subdevices_t, + me_query_number_subdevices, + me_device_query_number_subdevices, + (device, &karg.number)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_channels", + me_query_number_channels_t, + me_query_number_channels, + me_device_query_number_channels, + (device, karg.subdevice, &karg.number)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_by_type", + me_query_subdevice_by_type_t, + me_query_subdevice_by_type, + me_device_query_subdevice_by_type, + (device, + karg.start_subdevice, + karg.type, karg.subtype, &karg.subdevice)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_type", + me_query_subdevice_type_t, + me_query_subdevice_type, + me_device_query_subdevice_type, + (device, karg.subdevice, &karg.type, &karg.subtype)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_caps", + me_query_subdevice_caps_t, + me_query_subdevice_caps, + me_device_query_subdevice_caps, + (device, karg.subdevice, &karg.caps)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_caps_args", + me_query_subdevice_caps_args_t, + me_query_subdevice_caps_args, + me_device_query_subdevice_caps_args, + (device, karg.subdevice, karg.cap, karg.args, + karg.count)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_ranges", + me_query_number_ranges_t, + me_query_number_ranges, + me_device_query_number_ranges, + (device, karg.subdevice, karg.unit, &karg.number)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_range_by_min_max", + me_query_range_by_min_max_t, + me_query_range_by_min_max, + me_device_query_range_by_min_max, + (device, + karg.subdevice, + karg.unit, + &karg.min, &karg.max, &karg.max_data, &karg.range)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_range_info", + me_query_range_info_t, + me_query_range_info, + me_device_query_range_info, + (device, + karg.subdevice, + karg.range, + &karg.unit, &karg.min, &karg.max, &karg.max_data)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_timer", + me_query_timer_t, + me_query_timer, + me_device_query_timer, + (device, + karg.subdevice, + karg.timer, + &karg.base_frequency, + &karg.min_ticks, &karg.max_ticks)) + + ME_QUERY_MULTIPLEX_TEMPLATE("me_query_version_device_driver", + me_query_version_device_driver_t, + me_query_version_device_driver, + me_device_query_version_device_driver, + (device, &karg.version)) +#else +#error macro ME_QUERY_MULTIPLEX_TEMPLATE not defined +#endif + +/** ******************************************************************************** **/ + +static me_device_t *get_dummy_instance(unsigned short vendor_id, + unsigned short device_id, + unsigned int serial_no, + int bus_type, + int bus_no, int dev_no, int func_no) +{ + int err; + me_dummy_constructor_t constructor = NULL; + me_device_t *instance; + + PDEBUG("executed.\n"); + + if ((constructor = symbol_get(medummy_constructor)) == NULL) { + err = request_module(MEDUMMY_NAME); + + if (err) { + PERROR("Error while request for module %s.\n", + MEDUMMY_NAME); + return NULL; + } + + if ((constructor = symbol_get(medummy_constructor)) == NULL) { + PERROR("Can't get %s driver module constructor.\n", + MEDUMMY_NAME); + return NULL; + } + } + + if ((instance = (*constructor) (vendor_id, + device_id, + serial_no, + bus_type, + bus_no, dev_no, func_no)) == NULL) + symbol_put(medummy_constructor); + + return instance; +} + +static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id) +{ + int err; + me_pci_constructor_t constructor = NULL; +#ifdef BOSCH + me_bosch_constructor_t constructor_bosch = NULL; +#endif + me_device_t *n_device = NULL; + uint32_t device; + + char constructor_name[24] = "me0000_pci_constructor"; + char module_name[7] = "me0000"; + + PDEBUG("executed.\n"); + device = dev->device; + if ((device & 0xF000) == 0x6000) { // Exceptions: me61xx, me62xx, me63xx are handled by one driver. + device &= 0xF0FF; + } + + constructor_name[2] += (char)((device >> 12) & 0x000F); + constructor_name[3] += (char)((device >> 8) & 0x000F); + PDEBUG("constructor_name: %s\n", constructor_name); + module_name[2] += (char)((device >> 12) & 0x000F); + module_name[3] += (char)((device >> 8) & 0x000F); + PDEBUG("module_name: %s\n", module_name); + + if ((constructor = + (me_pci_constructor_t) __symbol_get(constructor_name)) == NULL) { + if (request_module(module_name)) { + PERROR("Error while request for module %s.\n", + module_name); + return -ENODEV; + } + + if ((constructor = + (me_pci_constructor_t) __symbol_get(constructor_name)) == + NULL) { + PERROR("Can't get %s driver module constructor.\n", + module_name); + return -ENODEV; + } + } +#ifdef BOSCH + if ((device & 0xF000) == 0x4000) { // Bosch build has differnt constructor for me4600. + if ((n_device = + (*constructor_bosch) (dev, me_bosch_fw)) == NULL) { + __symbol_put(constructor_name); + PERROR + ("Can't get device instance of %s driver module.\n", + module_name); + return -ENODEV; + } + } else { +#endif + if ((n_device = (*constructor) (dev)) == NULL) { + __symbol_put(constructor_name); + PERROR + ("Can't get device instance of %s driver module.\n", + module_name); + return -ENODEV; + } +#ifdef BOSCH + } +#endif + + insert_to_device_list(n_device); + err = + n_device->me_device_io_reset_device(n_device, NULL, + ME_IO_RESET_DEVICE_NO_FLAGS); + if (err) { + PERROR("Error while reseting device.\n"); + } else { + PDEBUG("Reseting device was sucessful.\n"); + } + return ME_ERRNO_SUCCESS; +} + +static void release_instance(me_device_t * device) +{ + int vendor_id; + int device_id; + int serial_no; + int bus_type; + int bus_no; + int dev_no; + int func_no; + int plugged; + + uint32_t dev_id; + + char constructor_name[24] = "me0000_pci_constructor"; + + PDEBUG("executed.\n"); + + device->me_device_query_info_device(device, + &vendor_id, + &device_id, + &serial_no, + &bus_type, + &bus_no, + &dev_no, &func_no, &plugged); + + dev_id = device_id; + device->me_device_destructor(device); + + if (plugged != ME_PLUGGED_IN) { + PDEBUG("release: medummy_constructor\n"); + + __symbol_put("medummy_constructor"); + } else { + if ((dev_id & 0xF000) == 0x6000) { // Exceptions: me61xx, me62xx, me63xx are handled by one driver. + dev_id &= 0xF0FF; + } + + constructor_name[2] += (char)((dev_id >> 12) & 0x000F); + constructor_name[3] += (char)((dev_id >> 8) & 0x000F); + PDEBUG("release: %s\n", constructor_name); + + __symbol_put(constructor_name); + } +} + +static int insert_to_device_list(me_device_t * n_device) +{ + me_device_t *o_device = NULL; + + struct list_head *pos; + int n_vendor_id; + int n_device_id; + int n_serial_no; + int n_bus_type; + int n_bus_no; + int n_dev_no; + int n_func_no; + int n_plugged; + int o_vendor_id; + int o_device_id; + int o_serial_no; + int o_bus_type; + int o_bus_no; + int o_dev_no; + int o_func_no; + int o_plugged; + + PDEBUG("executed.\n"); + + n_device->me_device_query_info_device(n_device, + &n_vendor_id, + &n_device_id, + &n_serial_no, + &n_bus_type, + &n_bus_no, + &n_dev_no, + &n_func_no, &n_plugged); + + down_write(&me_rwsem); + + list_for_each(pos, &me_device_list) { + o_device = list_entry(pos, me_device_t, list); + o_device->me_device_query_info_device(o_device, + &o_vendor_id, + &o_device_id, + &o_serial_no, + &o_bus_type, + &o_bus_no, + &o_dev_no, + &o_func_no, &o_plugged); + + if (o_plugged == ME_PLUGGED_OUT) { + if (((o_vendor_id == n_vendor_id) && + (o_device_id == n_device_id) && + (o_serial_no == n_serial_no) && + (o_bus_type == n_bus_type)) || + ((o_vendor_id == n_vendor_id) && + (o_device_id == n_device_id) && + (o_bus_type == n_bus_type) && + (o_bus_no == n_bus_no) && + (o_dev_no == n_dev_no) && + (o_func_no == n_func_no))) { + n_device->list.prev = pos->prev; + n_device->list.next = pos->next; + pos->prev->next = &n_device->list; + pos->next->prev = &n_device->list; + release_instance(o_device); + break; + } + } + } + + if (pos == &me_device_list) { + list_add_tail(&n_device->list, &me_device_list); + } + + up_write(&me_rwsem); + + return 0; +} + +static void me_remove_pci(struct pci_dev *dev) +{ + int vendor_id = dev->vendor; + int device_id = dev->device; + int subsystem_vendor = dev->subsystem_vendor; + int subsystem_device = dev->subsystem_device; + int serial_no = (subsystem_device << 16) | subsystem_vendor; + + PDEBUG("executed.\n"); + + PINFO("Vendor id = 0x%08X\n", vendor_id); + PINFO("Device id = 0x%08X\n", device_id); + PINFO("Serial Number = 0x%08X\n", serial_no); + + replace_with_dummy(vendor_id, device_id, serial_no); +} + +static int replace_with_dummy(int vendor_id, int device_id, int serial_no) +{ + + struct list_head *pos; + me_device_t *n_device = NULL; + me_device_t *o_device = NULL; + int o_vendor_id; + int o_device_id; + int o_serial_no; + int o_bus_type; + int o_bus_no; + int o_dev_no; + int o_func_no; + int o_plugged; + + PDEBUG("executed.\n"); + + down_write(&me_rwsem); + + list_for_each(pos, &me_device_list) { + o_device = list_entry(pos, me_device_t, list); + o_device->me_device_query_info_device(o_device, + &o_vendor_id, + &o_device_id, + &o_serial_no, + &o_bus_type, + &o_bus_no, + &o_dev_no, + &o_func_no, &o_plugged); + + if (o_plugged == ME_PLUGGED_IN) { + if (((o_vendor_id == vendor_id) && + (o_device_id == device_id) && + (o_serial_no == serial_no))) { + n_device = get_dummy_instance(o_vendor_id, + o_device_id, + o_serial_no, + o_bus_type, + o_bus_no, + o_dev_no, + o_func_no); + + if (!n_device) { + up_write(&me_rwsem); + PERROR("Cannot get dummy instance.\n"); + return 1; + } + + n_device->list.prev = pos->prev; + + n_device->list.next = pos->next; + pos->prev->next = &n_device->list; + pos->next->prev = &n_device->list; + release_instance(o_device); + break; + } + } + } + + up_write(&me_rwsem); + + return 0; +} + +static void clear_device_list(void) +{ + + struct list_head *entry; + me_device_t *device; + + // Clear the device info list . + down_write(&me_rwsem); + + while (!list_empty(&me_device_list)) { + entry = me_device_list.next; + device = list_entry(entry, me_device_t, list); + list_del(entry); + release_instance(device); + } + + up_write(&me_rwsem); +} + +static int lock_driver(struct file *filep, int lock, int flags) +{ + int err = ME_ERRNO_SUCCESS; + me_device_t *device; + + PDEBUG("executed.\n"); + + down_read(&me_rwsem); + + spin_lock(&me_lock); + + switch (lock) { + + case ME_LOCK_SET: + if (me_count) { + PERROR + ("Driver System is currently used by another process.\n"); + err = ME_ERRNO_USED; + } else if ((me_filep != NULL) && (me_filep != filep)) { + PERROR + ("Driver System is already logged by another process.\n"); + err = ME_ERRNO_LOCKED; + } else { + list_for_each_entry(device, &me_device_list, list) { + err = + device->me_device_lock_device(device, filep, + ME_LOCK_CHECK, + flags); + + if (err) + break; + } + + if (!err) + me_filep = filep; + } + + break; + + case ME_LOCK_RELEASE: + if ((me_filep != NULL) && (me_filep != filep)) { + err = ME_ERRNO_SUCCESS; + } else { + list_for_each_entry(device, &me_device_list, list) { + device->me_device_lock_device(device, filep, + ME_LOCK_RELEASE, + flags); + } + + me_filep = NULL; + } + + break; + + default: + PERROR("Invalid lock specified.\n"); + + err = ME_ERRNO_INVALID_LOCK; + + break; + } + + spin_unlock(&me_lock); + + up_read(&me_rwsem); + + return err; +} + +static int me_lock_driver(struct file *filep, me_lock_driver_t * arg) +{ + int err = 0; + + me_lock_driver_t lock; + + PDEBUG("executed.\n"); + + err = copy_from_user(&lock, arg, sizeof(me_lock_driver_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + + lock.errno = lock_driver(filep, lock.lock, lock.flags); + + err = copy_to_user(arg, &lock, sizeof(me_lock_driver_t)); + + if (err) { + PERROR("Can't copy query back to user space.\n"); + return -EFAULT; + } + + return ME_ERRNO_SUCCESS; +} + +static int me_open(struct inode *inode_ptr, struct file *filep) +{ + + PDEBUG("executed.\n"); + // Nothing to do here. + return 0; +} + +static int me_release(struct inode *inode_ptr, struct file *filep) +{ + + PDEBUG("executed.\n"); + lock_driver(filep, ME_LOCK_RELEASE, ME_LOCK_DRIVER_NO_FLAGS); + + return 0; +} + +static int me_query_version_main_driver(struct file *filep, + me_query_version_main_driver_t * arg) +{ + int err; + me_query_version_main_driver_t karg; + + PDEBUG("executed.\n"); + + karg.version = ME_VERSION_DRIVER; + karg.errno = ME_ERRNO_SUCCESS; + + err = copy_to_user(arg, &karg, sizeof(me_query_version_main_driver_t)); + + if (err) { + PERROR("Can't copy query back to user space.\n"); + return -EFAULT; + } + + return 0; +} + +static int me_config_load_device(struct file *filep, + me_cfg_device_entry_t * karg, int device_no) +{ + + int err = ME_ERRNO_SUCCESS; + int k = 0; + + struct list_head *pos = NULL; + me_device_t *device = NULL; + + PDEBUG("executed.\n"); + + list_for_each(pos, &me_device_list) { + if (k == device_no) { + device = list_entry(pos, me_device_t, list); + break; + } + + k++; + } + + if (pos == &me_device_list) { + PERROR("Invalid device number specified.\n"); + return ME_ERRNO_INVALID_DEVICE; + } else { + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Resource is locked by another process.\n"); + return ME_ERRNO_LOCKED; + } else { + me_count++; + spin_unlock(&me_lock); + + err = + device->me_device_config_load(device, filep, karg); + + spin_lock(&me_lock); + me_count--; + spin_unlock(&me_lock); + } + } + + return err; +} + +static int me_config_load(struct file *filep, me_config_load_t * arg) +{ + int err; + int i; + me_config_load_t cfg_setup; + me_config_load_t karg_cfg_setup; + + struct list_head *pos = NULL; + + struct list_head new_list; + me_device_t *o_device; + me_device_t *n_device; + int o_vendor_id; + int o_device_id; + int o_serial_no; + int o_bus_type; + int o_bus_no; + int o_dev_no; + int o_func_no; + int o_plugged; + + PDEBUG("executed.\n"); + + // Copy argument to kernel space. + err = copy_from_user(&karg_cfg_setup, arg, sizeof(me_config_load_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + // Allocate kernel buffer for device list. + cfg_setup.device_list = + kmalloc(sizeof(me_cfg_device_entry_t) * karg_cfg_setup.count, + GFP_KERNEL); + + if (!cfg_setup.device_list) { + PERROR("Can't get buffer %li for device list.\n", + sizeof(me_cfg_device_entry_t) * karg_cfg_setup.count); + return -ENOMEM; + } + // Copy device list to kernel space. + err = + copy_from_user(cfg_setup.device_list, karg_cfg_setup.device_list, + sizeof(me_cfg_device_entry_t) * + karg_cfg_setup.count); + + if (err) { + PERROR("Can't copy device list to kernel space.\n"); + kfree(cfg_setup.device_list); + return -EFAULT; + } + + cfg_setup.count = karg_cfg_setup.count; + + INIT_LIST_HEAD(&new_list); + + down_write(&me_rwsem); + + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Driver System is logged by another process.\n"); + karg_cfg_setup.errno = ME_ERRNO_LOCKED; + } else { + me_count++; + spin_unlock(&me_lock); + + for (i = 0; i < karg_cfg_setup.count; i++) { + PDEBUG("me_config_load() device=%d.\n", i); + if (cfg_setup.device_list[i].tcpip.access_type == + ME_ACCESS_TYPE_LOCAL) { + list_for_each(pos, &me_device_list) { + o_device = + list_entry(pos, me_device_t, list); + o_device-> + me_device_query_info_device + (o_device, &o_vendor_id, + &o_device_id, &o_serial_no, + &o_bus_type, &o_bus_no, &o_dev_no, + &o_func_no, &o_plugged); + + if (cfg_setup.device_list[i].info. + hw_location.bus_type == + ME_BUS_TYPE_PCI) { + if (((o_vendor_id == + cfg_setup.device_list[i]. + info.vendor_id) + && (o_device_id == + cfg_setup. + device_list[i].info. + device_id) + && (o_serial_no == + cfg_setup. + device_list[i].info. + serial_no) + && (o_bus_type == + cfg_setup. + device_list[i].info. + hw_location.bus_type)) + || + ((o_vendor_id == + cfg_setup.device_list[i]. + info.vendor_id) + && (o_device_id == + cfg_setup. + device_list[i].info. + device_id) + && (o_bus_type == + cfg_setup. + device_list[i].info. + hw_location.bus_type) + && (o_bus_no == + cfg_setup. + device_list[i].info. + hw_location.pci.bus_no) + && (o_dev_no == + cfg_setup. + device_list[i].info. + hw_location.pci. + device_no) + && (o_func_no == + cfg_setup. + device_list[i].info. + hw_location.pci. + function_no))) { + list_move_tail(pos, + &new_list); + break; + } + } +/* + else if (cfg_setup.device_list[i].info.hw_location.bus_type == ME_BUS_TYPE_USB) + { + if (((o_vendor_id == cfg_setup.device_list[i].info.vendor_id) && + (o_device_id == cfg_setup.device_list[i].info.device_id) && + (o_serial_no == cfg_setup.device_list[i].info.serial_no) && + (o_bus_type == cfg_setup.device_list[i].info.hw_location.bus_type)) || + ((o_vendor_id == cfg_setup.device_list[i].info.vendor_id) && + (o_device_id == cfg_setup.device_list[i].info.device_id) && + (o_bus_type == cfg_setup.device_list[i].info.hw_location.bus_type) && + (o_bus_no == cfg_setup.device_list[i].info.hw_location.usb.root_hub_no))) + { + list_move_tail(pos, &new_list); + break; + } + } +*/ + else { + PERROR("Wrong bus type: %d.\n", + cfg_setup.device_list[i]. + info.hw_location. + bus_type); + } + } + + if (pos == &me_device_list) { // Device is not already in the list + if (cfg_setup.device_list[i].info. + hw_location.bus_type == + ME_BUS_TYPE_PCI) { + n_device = + get_dummy_instance + (cfg_setup.device_list[i]. + info.vendor_id, + cfg_setup.device_list[i]. + info.device_id, + cfg_setup.device_list[i]. + info.serial_no, + cfg_setup.device_list[i]. + info.hw_location.bus_type, + cfg_setup.device_list[i]. + info.hw_location.pci. + bus_no, + cfg_setup.device_list[i]. + info.hw_location.pci. + device_no, + cfg_setup.device_list[i]. + info.hw_location.pci. + function_no); + + if (!n_device) { + PERROR + ("Can't get dummy instance.\n"); + kfree(cfg_setup. + device_list); + spin_lock(&me_lock); + me_count--; + spin_unlock(&me_lock); + up_write(&me_rwsem); + return -EFAULT; + } + + list_add_tail(&n_device->list, + &new_list); + } +/* + else if (cfg_setup.device_list[i].info.hw_location.bus_type == ME_BUS_TYPE_USB) + { + n_device = get_dummy_instance( + cfg_setup.device_list[i].info.vendor_id, + cfg_setup.device_list[i].info.device_id, + cfg_setup.device_list[i].info.serial_no, + cfg_setup.device_list[i].info.hw_location.bus_type, + cfg_setup.device_list[i].info.hw_location.usb.root_hub_no, + 0, + 0); + + if (!n_device) + { + PERROR("Can't get dummy instance.\n"); + kfree(cfg_setup.device_list); + spin_lock(&me_lock); + me_count--; + spin_unlock(&me_lock); + up_write(&me_rwsem); + return -EFAULT; + } + + list_add_tail(&n_device->list, &new_list); + } +*/ + } + } else { + n_device = get_dummy_instance(0, + 0, 0, 0, 0, 0, 0); + + if (!n_device) { + PERROR("Can't get dummy instance.\n"); + kfree(cfg_setup.device_list); + spin_lock(&me_lock); + me_count--; + spin_unlock(&me_lock); + up_write(&me_rwsem); + return -EFAULT; + } + + list_add_tail(&n_device->list, &new_list); + } + } + + while (!list_empty(&me_device_list)) { + o_device = + list_entry(me_device_list.next, me_device_t, list); + o_device->me_device_query_info_device(o_device, + &o_vendor_id, + &o_device_id, + &o_serial_no, + &o_bus_type, + &o_bus_no, + &o_dev_no, + &o_func_no, + &o_plugged); + + if (o_plugged == ME_PLUGGED_IN) { + list_move_tail(me_device_list.next, &new_list); + } else { + list_del(me_device_list.next); + release_instance(o_device); + } + } + + // Move temporary new list to global driver list. + list_splice(&new_list, &me_device_list); + + karg_cfg_setup.errno = ME_ERRNO_SUCCESS; + } + + for (i = 0; i < cfg_setup.count; i++) { + + karg_cfg_setup.errno = + me_config_load_device(filep, &cfg_setup.device_list[i], i); + if (karg_cfg_setup.errno) { + PERROR("me_config_load_device(%d)=%d\n", i, + karg_cfg_setup.errno); + break; + } + } + + spin_lock(&me_lock); + + me_count--; + spin_unlock(&me_lock); + up_write(&me_rwsem); + + err = copy_to_user(arg, &karg_cfg_setup, sizeof(me_config_load_t)); + + if (err) { + PERROR("Can't copy config list to user space.\n"); + kfree(cfg_setup.device_list); + return -EFAULT; + } + + kfree(cfg_setup.device_list); + return 0; +} + +static int me_io_stream_start(struct file *filep, me_io_stream_start_t * arg) +{ + int err; + int i, k; + + struct list_head *pos; + me_device_t *device; + me_io_stream_start_t karg; + meIOStreamStart_t *list; + + PDEBUG("executed.\n"); + + err = copy_from_user(&karg, arg, sizeof(me_io_stream_start_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + + karg.errno = ME_ERRNO_SUCCESS; + + list = kmalloc(sizeof(meIOStreamStart_t) * karg.count, GFP_KERNEL); + + if (!list) { + PERROR("Can't get buffer for start list.\n"); + return -ENOMEM; + } + + err = + copy_from_user(list, karg.start_list, + sizeof(meIOStreamStart_t) * karg.count); + + if (err) { + PERROR("Can't copy start list to kernel space.\n"); + kfree(list); + return -EFAULT; + } + + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Driver System is logged by another process.\n"); + + for (i = 0; i < karg.count; i++) { + list[i].iErrno = ME_ERRNO_LOCKED; + } + } else { + me_count++; + spin_unlock(&me_lock); + + for (i = 0; i < karg.count; i++) { + down_read(&me_rwsem); + k = 0; + list_for_each(pos, &me_device_list) { + if (k == list[i].iDevice) { + device = + list_entry(pos, me_device_t, list); + break; + } + + k++; + } + + if (pos == &me_device_list) { + up_read(&me_rwsem); + PERROR("Invalid device number specified.\n"); + list[i].iErrno = ME_ERRNO_INVALID_DEVICE; + karg.errno = ME_ERRNO_INVALID_DEVICE; + break; + } else { + list[i].iErrno = + device->me_device_io_stream_start(device, + filep, + list[i]. + iSubdevice, + list[i]. + iStartMode, + list[i]. + iTimeOut, + list[i]. + iFlags); + + if (list[i].iErrno) { + up_read(&me_rwsem); + karg.errno = list[i].iErrno; + break; + } + } + + up_read(&me_rwsem); + } + + spin_lock(&me_lock); + + me_count--; + spin_unlock(&me_lock); + } + + err = copy_to_user(arg, &karg, sizeof(me_io_stream_start_t)); + + if (err) { + PERROR("Can't copy arguments to user space.\n"); + kfree(list); + return -EFAULT; + } + + err = + copy_to_user(karg.start_list, list, + sizeof(meIOStreamStart_t) * karg.count); + + if (err) { + PERROR("Can't copy start list to user space.\n"); + kfree(list); + return -EFAULT; + } + + kfree(list); + + return err; +} + +static int me_io_single(struct file *filep, me_io_single_t * arg) +{ + int err; + int i, k; + + struct list_head *pos; + me_device_t *device; + me_io_single_t karg; + meIOSingle_t *list; + + PDEBUG("executed.\n"); + + err = copy_from_user(&karg, arg, sizeof(me_io_single_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + + karg.errno = ME_ERRNO_SUCCESS; + + list = kmalloc(sizeof(meIOSingle_t) * karg.count, GFP_KERNEL); + + if (!list) { + PERROR("Can't get buffer for single list.\n"); + return -ENOMEM; + } + + err = + copy_from_user(list, karg.single_list, + sizeof(meIOSingle_t) * karg.count); + + if (err) { + PERROR("Can't copy single list to kernel space.\n"); + kfree(list); + return -EFAULT; + } + + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Driver System is logged by another process.\n"); + + for (i = 0; i < karg.count; i++) { + list[i].iErrno = ME_ERRNO_LOCKED; + } + } else { + me_count++; + spin_unlock(&me_lock); + + for (i = 0; i < karg.count; i++) { + k = 0; + + down_read(&me_rwsem); + + list_for_each(pos, &me_device_list) { + if (k == list[i].iDevice) { + device = + list_entry(pos, me_device_t, list); + break; + } + + k++; + } + + if (pos == &me_device_list) { + up_read(&me_rwsem); + PERROR("Invalid device number specified.\n"); + list[i].iErrno = ME_ERRNO_INVALID_DEVICE; + karg.errno = ME_ERRNO_INVALID_DEVICE; + break; + } else { + if (list[i].iDir == ME_DIR_OUTPUT) { + list[i].iErrno = + device-> + me_device_io_single_write(device, + filep, + list[i]. + iSubdevice, + list[i]. + iChannel, + list[i]. + iValue, + list[i]. + iTimeOut, + list[i]. + iFlags); + + if (list[i].iErrno) { + up_read(&me_rwsem); + karg.errno = list[i].iErrno; + break; + } + } else if (list[i].iDir == ME_DIR_INPUT) { + list[i].iErrno = + device-> + me_device_io_single_read(device, + filep, + list[i]. + iSubdevice, + list[i]. + iChannel, + &list[i]. + iValue, + list[i]. + iTimeOut, + list[i]. + iFlags); + + if (list[i].iErrno) { + up_read(&me_rwsem); + karg.errno = list[i].iErrno; + break; + } + } else { + up_read(&me_rwsem); + PERROR + ("Invalid single direction specified.\n"); + list[i].iErrno = ME_ERRNO_INVALID_DIR; + karg.errno = ME_ERRNO_INVALID_DIR; + break; + } + } + + up_read(&me_rwsem); + } + + spin_lock(&me_lock); + + me_count--; + spin_unlock(&me_lock); + } + + err = copy_to_user(arg, &karg, sizeof(me_io_single_t)); + + if (err) { + PERROR("Can't copy arguments to user space.\n"); + return -EFAULT; + } + + err = + copy_to_user(karg.single_list, list, + sizeof(meIOSingle_t) * karg.count); + + if (err) { + PERROR("Can't copy single list to user space.\n"); + kfree(list); + return -EFAULT; + } + + kfree(list); + + return err; +} + +static int me_io_stream_config(struct file *filep, me_io_stream_config_t * arg) +{ + int err; + int k = 0; + + struct list_head *pos; + me_device_t *device; + me_io_stream_config_t karg; + meIOStreamConfig_t *list; + + PDEBUG("executed.\n"); + + err = copy_from_user(&karg, arg, sizeof(me_io_stream_config_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + + list = kmalloc(sizeof(meIOStreamConfig_t) * karg.count, GFP_KERNEL); + + if (!list) { + PERROR("Can't get buffer for config list.\n"); + return -ENOMEM; + } + + err = + copy_from_user(list, karg.config_list, + sizeof(meIOStreamConfig_t) * karg.count); + + if (err) { + PERROR("Can't copy config list to kernel space.\n"); + kfree(list); + return -EFAULT; + } + + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Driver System is logged by another process.\n"); + karg.errno = ME_ERRNO_LOCKED; + } else { + me_count++; + spin_unlock(&me_lock); + + down_read(&me_rwsem); + + list_for_each(pos, &me_device_list) { + if (k == karg.device) { + device = list_entry(pos, me_device_t, list); + break; + } + + k++; + } + + if (pos == &me_device_list) { + PERROR("Invalid device number specified.\n"); + karg.errno = ME_ERRNO_INVALID_DEVICE; + } else { + karg.errno = + device->me_device_io_stream_config(device, filep, + karg.subdevice, + list, karg.count, + &karg.trigger, + karg. + fifo_irq_threshold, + karg.flags); + } + + up_read(&me_rwsem); + + spin_lock(&me_lock); + me_count--; + spin_unlock(&me_lock); + } + + err = copy_to_user(arg, &karg, sizeof(me_io_stream_config_t)); + + if (err) { + PERROR("Can't copy back to user space.\n"); + kfree(list); + return -EFAULT; + } + + kfree(list); + + return err; +} + +static int me_query_number_devices(struct file *filep, + me_query_number_devices_t * arg) +{ + int err; + me_query_number_devices_t karg; + + struct list_head *pos; + + PDEBUG("executed.\n"); + + karg.number = 0; + down_read(&me_rwsem); + list_for_each(pos, &me_device_list) { + karg.number++; + } + + up_read(&me_rwsem); + + karg.errno = ME_ERRNO_SUCCESS; + + err = copy_to_user(arg, &karg, sizeof(me_query_number_devices_t)); + + if (err) { + PERROR("Can't copy query back to user space.\n"); + return -EFAULT; + } + + return 0; +} + +static int me_io_stream_stop(struct file *filep, me_io_stream_stop_t * arg) +{ + int err; + int i, k; + + struct list_head *pos; + me_device_t *device; + me_io_stream_stop_t karg; + meIOStreamStop_t *list; + + PDEBUG("executed.\n"); + + err = copy_from_user(&karg, arg, sizeof(me_io_stream_stop_t)); + + if (err) { + PERROR("Can't copy arguments to kernel space.\n"); + return -EFAULT; + } + + karg.errno = ME_ERRNO_SUCCESS; + + list = kmalloc(sizeof(meIOStreamStop_t) * karg.count, GFP_KERNEL); + + if (!list) { + PERROR("Can't get buffer for stop list.\n"); + return -ENOMEM; + } + + err = + copy_from_user(list, karg.stop_list, + sizeof(meIOStreamStop_t) * karg.count); + + if (err) { + PERROR("Can't copy stop list to kernel space.\n"); + kfree(list); + return -EFAULT; + } + + spin_lock(&me_lock); + + if ((me_filep != NULL) && (me_filep != filep)) { + spin_unlock(&me_lock); + PERROR("Driver System is logged by another process.\n"); + + for (i = 0; i < karg.count; i++) { + list[i].iErrno = ME_ERRNO_LOCKED; + } + } else { + me_count++; + spin_unlock(&me_lock); + + for (i = 0; i < karg.count; i++) { + k = 0; + down_read(&me_rwsem); + list_for_each(pos, &me_device_list) { + if (k == list[i].iDevice) { + device = + list_entry(pos, me_device_t, list); + break; + } + + k++; + } + + if (pos == &me_device_list) { + up_read(&me_rwsem); + PERROR("Invalid device number specified.\n"); + list[i].iErrno = ME_ERRNO_INVALID_DEVICE; + karg.errno = ME_ERRNO_INVALID_DEVICE; + break; + } else { + list[i].iErrno = + device->me_device_io_stream_stop(device, + filep, + list[i]. + iSubdevice, + list[i]. + iStopMode, + list[i]. + iFlags); + + if (list[i].iErrno) { + up_read(&me_rwsem); + karg.errno = list[i].iErrno; + break; + } + } + + up_read(&me_rwsem); + } + + spin_lock(&me_lock); + + me_count--; + spin_unlock(&me_lock); + } + + err = copy_to_user(arg, &karg, sizeof(me_io_stream_stop_t)); + + if (err) { + PERROR("Can't copy arguments to user space.\n"); + return -EFAULT; + } + + err = + copy_to_user(karg.stop_list, list, + sizeof(meIOStreamStop_t) * karg.count); + + if (err) { + PERROR("Can't copy stop list to user space.\n"); + kfree(list); + return -EFAULT; + } + + kfree(list); + + return err; +} + +/* //me_probe_usb +static int me_probe_usb(struct usb_interface *interface, const struct usb_device_id *id) +{ + //int err; + //me_usb_constructor_t *constructor = NULL; + me_device_t *n_device = NULL; + + PDEBUG("executed.\n"); + + switch (id->idProduct) + { + case USB_DEVICE_ID_MEPHISTO_S1: + if((constructor = symbol_get(mephisto_s1_constructor)) == NULL){ + err = request_module(MEPHISTO_S1_NAME); + if(err){ + PERROR("Error while request for module %s.\n", MEPHISTO_S1_NAME); + return -ENODEV; + } + if((constructor = symbol_get(mephisto_s1_constructor)) == NULL){ + PERROR("Can't get %s driver module constructor.\n", MEPHISTO_S1_NAME); + return -ENODEV; + } + } + + if((n_device = (*constructor)(interface)) == NULL){ + symbol_put(mephisto_s1_constructor); + PERROR("Can't get device instance of %s driver module.\n", MEPHISTO_S1_NAME); + return -ENODEV; + } + + break; + + default: + PERROR("Invalid product id.\n"); + + return -EINVAL; + } + + return insert_to_device_list(n_device); +} +*/ + +/* //me_disconnect_usb +static void me_disconnect_usb(struct usb_interface *interface) +{ + + struct usb_device *device = interface_to_usbdev(interface); + int vendor_id = device->descriptor.idVendor; + int device_id = device->descriptor.idProduct; + int serial_no; + + sscanf(&device->serial[2], "%x", &serial_no); + + PDEBUG("executed.\n"); + + PINFO("Vendor id = 0x%08X\n", vendor_id); + PINFO("Device id = 0x%08X\n", device_id); + PINFO("Serial Number = 0x%08X\n", serial_no); + + replace_with_dummy(vendor_id, device_id, serial_no); +} +*/ + +static int me_ioctl(struct inode *inodep, + struct file *filep, unsigned int service, unsigned long arg) +{ + + PDEBUG("executed.\n"); + + if (_IOC_TYPE(service) != MEMAIN_MAGIC) { + PERROR("Invalid magic number.\n"); + return -ENOTTY; + } + + PDEBUG("service number: 0x%x.\n", service); + + switch (service) { + case ME_IO_IRQ_ENABLE: + return me_io_irq_start(filep, (me_io_irq_start_t *) arg); + + case ME_IO_IRQ_WAIT: + return me_io_irq_wait(filep, (me_io_irq_wait_t *) arg); + + case ME_IO_IRQ_DISABLE: + return me_io_irq_stop(filep, (me_io_irq_stop_t *) arg); + + case ME_IO_RESET_DEVICE: + return me_io_reset_device(filep, (me_io_reset_device_t *) arg); + + case ME_IO_RESET_SUBDEVICE: + return me_io_reset_subdevice(filep, + (me_io_reset_subdevice_t *) arg); + + case ME_IO_SINGLE_CONFIG: + return me_io_single_config(filep, + (me_io_single_config_t *) arg); + + case ME_IO_SINGLE: + return me_io_single(filep, (me_io_single_t *) arg); + + case ME_IO_STREAM_CONFIG: + return me_io_stream_config(filep, + (me_io_stream_config_t *) arg); + + case ME_IO_STREAM_NEW_VALUES: + return me_io_stream_new_values(filep, + (me_io_stream_new_values_t *) + arg); + + case ME_IO_STREAM_READ: + return me_io_stream_read(filep, (me_io_stream_read_t *) arg); + + case ME_IO_STREAM_START: + return me_io_stream_start(filep, (me_io_stream_start_t *) arg); + + case ME_IO_STREAM_STATUS: + return me_io_stream_status(filep, + (me_io_stream_status_t *) arg); + + case ME_IO_STREAM_STOP: + return me_io_stream_stop(filep, (me_io_stream_stop_t *) arg); + + case ME_IO_STREAM_WRITE: + return me_io_stream_write(filep, (me_io_stream_write_t *) arg); + + case ME_LOCK_DRIVER: + return me_lock_driver(filep, (me_lock_driver_t *) arg); + + case ME_LOCK_DEVICE: + return me_lock_device(filep, (me_lock_device_t *) arg); + + case ME_LOCK_SUBDEVICE: + return me_lock_subdevice(filep, (me_lock_subdevice_t *) arg); + + case ME_QUERY_INFO_DEVICE: + return me_query_info_device(filep, + (me_query_info_device_t *) arg); + + case ME_QUERY_DESCRIPTION_DEVICE: + return me_query_description_device(filep, + (me_query_description_device_t + *) arg); + + case ME_QUERY_NAME_DEVICE: + return me_query_name_device(filep, + (me_query_name_device_t *) arg); + + case ME_QUERY_NAME_DEVICE_DRIVER: + return me_query_name_device_driver(filep, + (me_query_name_device_driver_t + *) arg); + + case ME_QUERY_NUMBER_DEVICES: + return me_query_number_devices(filep, + (me_query_number_devices_t *) + arg); + + case ME_QUERY_NUMBER_SUBDEVICES: + return me_query_number_subdevices(filep, + (me_query_number_subdevices_t + *) arg); + + case ME_QUERY_NUMBER_CHANNELS: + return me_query_number_channels(filep, + (me_query_number_channels_t *) + arg); + + case ME_QUERY_NUMBER_RANGES: + return me_query_number_ranges(filep, + (me_query_number_ranges_t *) arg); + + case ME_QUERY_RANGE_BY_MIN_MAX: + return me_query_range_by_min_max(filep, + (me_query_range_by_min_max_t *) + arg); + + case ME_QUERY_RANGE_INFO: + return me_query_range_info(filep, + (me_query_range_info_t *) arg); + + case ME_QUERY_SUBDEVICE_BY_TYPE: + return me_query_subdevice_by_type(filep, + (me_query_subdevice_by_type_t + *) arg); + + case ME_QUERY_SUBDEVICE_TYPE: + return me_query_subdevice_type(filep, + (me_query_subdevice_type_t *) + arg); + + case ME_QUERY_SUBDEVICE_CAPS: + return me_query_subdevice_caps(filep, + (me_query_subdevice_caps_t *) + arg); + + case ME_QUERY_SUBDEVICE_CAPS_ARGS: + return me_query_subdevice_caps_args(filep, + (me_query_subdevice_caps_args_t + *) arg); + + case ME_QUERY_TIMER: + return me_query_timer(filep, (me_query_timer_t *) arg); + + case ME_QUERY_VERSION_MAIN_DRIVER: + return me_query_version_main_driver(filep, + (me_query_version_main_driver_t + *) arg); + + case ME_QUERY_VERSION_DEVICE_DRIVER: + return me_query_version_device_driver(filep, + (me_query_version_device_driver_t + *) arg); + + case ME_CONFIG_LOAD: + return me_config_load(filep, (me_config_load_t *) arg); + } + + PERROR("Invalid ioctl number.\n"); + return -ENOTTY; +} + +// Init and exit of module. +static int memain_init(void) +{ + int result = 0; + dev_t dev = MKDEV(major, 0); + + PDEBUG("executed.\n"); + + // Register pci driver. This will return 0 if the PCI subsystem is not available. + result = pci_register_driver(&me_pci_driver); + + if (result < 0) { + PERROR("Can't register pci driver.\n"); + goto INIT_ERROR_1; + } + +/* + // Register usb driver. This will return -ENODEV if no USB subsystem is available. + result = usb_register(&me_usb_driver); + + if (result) + { + if (result == -ENODEV) + { + PERROR("No USB subsystem available.\n"); + } + else + { + PERROR("Can't register usb driver.\n"); + goto INIT_ERROR_2; + } + } +*/ + // Register the character device. + if (major) { + result = register_chrdev_region(dev, 1, MEMAIN_NAME); + } else { + result = alloc_chrdev_region(&dev, 0, 1, MEMAIN_NAME); + major = MAJOR(dev); + } + + if (result < 0) { + PERROR("Can't get major driver no.\n"); + goto INIT_ERROR_3; + } + + cdevp = cdev_alloc(); + + if (!cdevp) { + PERROR("Can't get character device structure.\n"); + result = -ENOMEM; + goto INIT_ERROR_4; + } + + cdevp->ops = &me_file_operations; + + cdevp->owner = THIS_MODULE; + + result = cdev_add(cdevp, dev, 1); + + if (result < 0) { + PERROR("Cannot add character device structure.\n"); + goto INIT_ERROR_5; + } + + return 0; + + INIT_ERROR_5: + cdev_del(cdevp); + + INIT_ERROR_4: + unregister_chrdev_region(dev, 1); + + INIT_ERROR_3: +// usb_deregister(&me_usb_driver); + +//INIT_ERROR_2: + pci_unregister_driver(&me_pci_driver); + clear_device_list(); + + INIT_ERROR_1: + return result; +} + +static void __exit memain_exit(void) +{ + dev_t dev = MKDEV(major, 0); + + PDEBUG("executed.\n"); + + cdev_del(cdevp); + unregister_chrdev_region(dev, 1); + pci_unregister_driver(&me_pci_driver); +// usb_deregister(&me_usb_driver); + clear_device_list(); +} + +module_init(memain_init); +module_exit(memain_exit); + +// Administrative stuff for modinfo. +MODULE_AUTHOR + ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); +MODULE_DESCRIPTION("Central module for Meilhaus Driver System."); +MODULE_SUPPORTED_DEVICE("Meilhaus PCI/cPCI boards."); +MODULE_LICENSE("GPL"); + +#ifdef BOSCH +// Export the flag for the BOSCH firmware. +EXPORT_SYMBOL(me_bosch_fw); +#endif // BOSCH |