/** * @file medevice.c * * @brief Meilhaus device base class. * @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. */ #include "mecommon.h" #include "meinternal.h" #include "medefines.h" #include "meerror.h" #include "medebug.h" #include "medevice.h" #ifndef __KERNEL__ # define __KERNEL__ #endif static int me_device_io_irq_start(struct me_device *device, struct file *filep, int subdevice, int channel, int irq_source, int irq_edge, int irq_arg, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_irq_start(s, filep, channel, irq_source, irq_edge, irq_arg, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_irq_wait(struct me_device *device, struct file *filep, int subdevice, int channel, int *irq_count, int *value, int time_out, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_irq_wait(s, filep, channel, irq_count, value, time_out, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_irq_stop(struct me_device *device, struct file *filep, int subdevice, int channel, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_irq_stop(s, filep, channel, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_reset_device(struct me_device *device, struct file *filep, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; int i, n; PDEBUG("executed.\n"); /* Get the number of subdevices. */ n = me_slist_get_number_subdevices(&device->slist); // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } /* Reset every subdevice in list. */ for (i = 0; i < n; i++) { s = me_slist_get_subdevice(&device->slist, i); err = s->me_subdevice_io_reset_subdevice(s, filep, flags); if (err) { PERROR("Cannot reset subdevice.\n"); break; } } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_reset_subdevice(struct me_device *device, struct file *filep, int subdevice, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_reset_subdevice(s, filep, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_single_config(struct me_device *device, struct file *filep, int subdevice, int channel, int single_config, int ref, int trig_chan, int trig_type, int trig_edge, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_single_config(s, filep, channel, single_config, ref, trig_chan, trig_type, trig_edge, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_single_read(struct me_device *device, struct file *filep, int subdevice, int channel, int *value, int time_out, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_single_read(s, filep, channel, value, time_out, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_single_write(struct me_device *device, struct file *filep, int subdevice, int channel, int value, int time_out, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_single_write(s, filep, channel, value, time_out, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_config(struct me_device *device, struct file *filep, int subdevice, meIOStreamConfig_t * config_list, int count, meIOStreamTrigger_t * trigger, int fifo_irq_threshold, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_config(s, filep, config_list, count, trigger, fifo_irq_threshold, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_new_values(struct me_device *device, struct file *filep, int subdevice, int time_out, int *count, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_new_values(s, filep, time_out, count, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_read(struct me_device *device, struct file *filep, int subdevice, int read_mode, int *values, int *count, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_read(s, filep, read_mode, values, count, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_start(struct me_device *device, struct file *filep, int subdevice, int start_mode, int time_out, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_start(s, filep, start_mode, time_out, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_status(struct me_device *device, struct file *filep, int subdevice, int wait, int *status, int *count, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_status(s, filep, wait, status, count, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_stop(struct me_device *device, struct file *filep, int subdevice, int stop_mode, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_stop(s, filep, stop_mode, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_io_stream_write(struct me_device *device, struct file *filep, int subdevice, int write_mode, int *values, int *count, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_io_stream_write(s, filep, write_mode, values, count, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_lock_device(struct me_device *device, struct file *filep, int lock, int flags) { PDEBUG("executed.\n"); return me_dlock_lock(&device->dlock, filep, lock, flags, &device->slist); } static int me_device_lock_subdevice(struct me_device *device, struct file *filep, int subdevice, int lock, int flags) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Enter device. err = me_dlock_enter(&device->dlock, filep); if (err) { PERROR("Cannot enter device.\n"); return err; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_lock_subdevice(s, filep, lock, flags); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } // Exit device. me_dlock_exit(&device->dlock, filep); return err; } static int me_device_query_description_device(struct me_device *device, char **description) { PDEBUG("executed.\n"); *description = device->device_description; return ME_ERRNO_SUCCESS; } static int me_device_query_info_device(struct me_device *device, int *vendor_id, int *device_id, int *serial_no, int *bus_type, int *bus_no, int *dev_no, int *func_no, int *plugged) { PDEBUG("executed.\n"); if (device->bus_type == ME_BUS_TYPE_PCI) { *vendor_id = device->info.pci.vendor_id; *device_id = device->info.pci.device_id; *serial_no = device->info.pci.serial_no; *bus_type = ME_BUS_TYPE_PCI; *bus_no = device->info.pci.pci_bus_no; *dev_no = device->info.pci.pci_dev_no; *func_no = device->info.pci.pci_func_no; *plugged = ME_PLUGGED_IN; } else { *plugged = ME_PLUGGED_OUT; } return ME_ERRNO_SUCCESS; } static int me_device_query_name_device(struct me_device *device, char **name) { PDEBUG("executed.\n"); *name = device->device_name; return ME_ERRNO_SUCCESS; } static int me_device_query_name_device_driver(struct me_device *device, char **name) { PDEBUG("executed.\n"); *name = device->driver_name; return ME_ERRNO_SUCCESS; } static int me_device_query_number_subdevices(struct me_device *device, int *number) { PDEBUG("executed.\n"); return me_slist_query_number_subdevices(&device->slist, number); } static int me_device_query_number_channels(struct me_device *device, int subdevice, int *number) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_number_channels(s, number); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_number_ranges(struct me_device *device, int subdevice, int unit, int *count) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_number_ranges(s, unit, count); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_range_by_min_max(struct me_device *device, int subdevice, int unit, int *min, int *max, int *maxdata, int *range) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_range_by_min_max(s, unit, min, max, maxdata, range); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_range_info(struct me_device *device, int subdevice, int range, int *unit, int *min, int *max, int *maxdata) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_range_info(s, range, unit, min, max, maxdata); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_subdevice_by_type(struct me_device *device, int start_subdevice, int type, int subtype, int *subdevice) { PDEBUG("executed.\n"); return me_slist_get_subdevice_by_type(&device->slist, start_subdevice, type, subtype, subdevice); } static int me_device_query_subdevice_type(struct me_device *device, int subdevice, int *type, int *subtype) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_subdevice_type(s, type, subtype); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_subdevice_caps(struct me_device *device, int subdevice, int *caps) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_subdevice_caps(s, caps); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_subdevice_caps_args(struct me_device *device, int subdevice, int cap, int *args, int count) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_subdevice_caps_args(s, cap, args, count); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_timer(struct me_device *device, int subdevice, int timer, int *base_frequency, uint64_t * min_ticks, uint64_t * max_ticks) { int err = ME_ERRNO_SUCCESS; me_subdevice_t *s; PDEBUG("executed.\n"); // Check subdevice index. if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { PERROR("Invalid subdevice.\n"); return ME_ERRNO_INVALID_SUBDEVICE; } // Get subdevice instance. s = me_slist_get_subdevice(&device->slist, subdevice); if (s) { // Call subdevice method. err = s->me_subdevice_query_timer(s, timer, base_frequency, min_ticks, max_ticks); } else { // Something really bad happened. PERROR("Cannot get subdevice instance.\n"); err = ME_ERRNO_INTERNAL; } return err; } static int me_device_query_version_device_driver(struct me_device *device, int *version) /** @todo Versions shold be read from driver. I must overwrite this function in each module. Here should be returned an error! */ { PDEBUG("executed.\n"); *version = ME_VERSION_DRIVER; return ME_ERRNO_SUCCESS; } static int me_device_config_load(struct me_device *device, struct file *filep, me_cfg_device_entry_t * config) { PDEBUG("executed.\n"); return ME_ERRNO_SUCCESS; //If no need for config return success. // return ME_ERRNO_NOT_SUPPORTED; } static void me_device_destructor(me_device_t * me_device) { PDEBUG("executed.\n"); me_device_deinit(me_device); kfree(me_device); } /* //me_device_usb_init int me_device_usb_init(me_device_t *me_device, struct usb_interface *interface) { PDEBUG("executed.\n"); return -1; } */ static int get_device_descriptions(uint16_t device_id, char **device_name, char **device_description, char **driver_name) /** @todo This is wrong concept! Static table has too strong limitations! * 'device_name' and 'driver_name' should be calculated from 'device_id' * 'device_description' should be read from device or moved to user space and handled by library! */ { PDEBUG("executed.\n"); switch (device_id) { case PCI_DEVICE_ID_MEILHAUS_ME1000: case PCI_DEVICE_ID_MEILHAUS_ME1000_A: case PCI_DEVICE_ID_MEILHAUS_ME1000_B: *device_name = ME1000_NAME_DEVICE_ME1000; *device_description = ME1000_DESCRIPTION_DEVICE_ME1000; *driver_name = ME1000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1400: *device_name = ME1400_NAME_DEVICE_ME1400; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME140A: *device_name = ME1400_NAME_DEVICE_ME1400A; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400A; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME140B: *device_name = ME1400_NAME_DEVICE_ME1400B; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400B; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME14E0: *device_name = ME1400_NAME_DEVICE_ME1400E; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400E; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME14EA: *device_name = ME1400_NAME_DEVICE_ME1400EA; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400EA; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME14EB: *device_name = ME1400_NAME_DEVICE_ME1400EB; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400EB; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME140C: *device_name = ME1400_NAME_DEVICE_ME1400C; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400C; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME140D: *device_name = ME1400_NAME_DEVICE_ME1400D; *device_description = ME1400_DESCRIPTION_DEVICE_ME1400D; *driver_name = ME1400_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1600_4U: *device_name = ME1600_NAME_DEVICE_ME16004U; *device_description = ME1600_DESCRIPTION_DEVICE_ME16004U; *driver_name = ME1600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1600_8U: *device_name = ME1600_NAME_DEVICE_ME16008U; *device_description = ME1600_DESCRIPTION_DEVICE_ME16008U; *driver_name = ME1600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1600_12U: *device_name = ME1600_NAME_DEVICE_ME160012U; *device_description = ME1600_DESCRIPTION_DEVICE_ME160012U; *driver_name = ME1600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1600_16U: *device_name = ME1600_NAME_DEVICE_ME160016U; *device_description = ME1600_DESCRIPTION_DEVICE_ME160016U; *driver_name = ME1600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I: *device_name = ME1600_NAME_DEVICE_ME160016U8I; *device_description = ME1600_DESCRIPTION_DEVICE_ME160016U8I; *driver_name = ME1600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4610: *device_name = ME4600_NAME_DEVICE_ME4610; *device_description = ME4600_DESCRIPTION_DEVICE_ME4610; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4650: *device_name = ME4600_NAME_DEVICE_ME4650; *device_description = ME4600_DESCRIPTION_DEVICE_ME4650; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4660: *device_name = ME4600_NAME_DEVICE_ME4660; *device_description = ME4600_DESCRIPTION_DEVICE_ME4660; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4660I: *device_name = ME4600_NAME_DEVICE_ME4660I; *device_description = ME4600_DESCRIPTION_DEVICE_ME4660I; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4660S: *device_name = ME4600_NAME_DEVICE_ME4660S; *device_description = ME4600_DESCRIPTION_DEVICE_ME4660S; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4660IS: *device_name = ME4600_NAME_DEVICE_ME4660IS; *device_description = ME4600_DESCRIPTION_DEVICE_ME4660IS; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4670: *device_name = ME4600_NAME_DEVICE_ME4670; *device_description = ME4600_DESCRIPTION_DEVICE_ME4670; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4670I: *device_name = ME4600_NAME_DEVICE_ME4670I; *device_description = ME4600_DESCRIPTION_DEVICE_ME4670I; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4670S: *device_name = ME4600_NAME_DEVICE_ME4670S; *device_description = ME4600_DESCRIPTION_DEVICE_ME4670S; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4670IS: *device_name = ME4600_NAME_DEVICE_ME4670IS; *device_description = ME4600_DESCRIPTION_DEVICE_ME4670IS; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4680: *device_name = ME4600_NAME_DEVICE_ME4680; *device_description = ME4600_DESCRIPTION_DEVICE_ME4680; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4680I: *device_name = ME4600_NAME_DEVICE_ME4680I; *device_description = ME4600_DESCRIPTION_DEVICE_ME4680I; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4680S: *device_name = ME4600_NAME_DEVICE_ME4680S; *device_description = ME4600_DESCRIPTION_DEVICE_ME4680S; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME4680IS: *device_name = ME4600_NAME_DEVICE_ME4680IS; *device_description = ME4600_DESCRIPTION_DEVICE_ME4680IS; *driver_name = ME4600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6004: *device_name = ME6000_NAME_DEVICE_ME60004; *device_description = ME6000_DESCRIPTION_DEVICE_ME60004; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6008: *device_name = ME6000_NAME_DEVICE_ME60008; *device_description = ME6000_DESCRIPTION_DEVICE_ME60008; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME600F: *device_name = ME6000_NAME_DEVICE_ME600016; *device_description = ME6000_DESCRIPTION_DEVICE_ME600016; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6014: *device_name = ME6000_NAME_DEVICE_ME6000I4; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I4; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6018: *device_name = ME6000_NAME_DEVICE_ME6000I8; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I8; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME601F: *device_name = ME6000_NAME_DEVICE_ME6000I16; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I16; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6034: *device_name = ME6000_NAME_DEVICE_ME6000ISLE4; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6038: *device_name = ME6000_NAME_DEVICE_ME6000ISLE8; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME603F: *device_name = ME6000_NAME_DEVICE_ME6000ISLE16; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6104: *device_name = ME6000_NAME_DEVICE_ME61004; *device_description = ME6000_DESCRIPTION_DEVICE_ME61004; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6108: *device_name = ME6000_NAME_DEVICE_ME61008; *device_description = ME6000_DESCRIPTION_DEVICE_ME61008; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME610F: *device_name = ME6000_NAME_DEVICE_ME610016; *device_description = ME6000_DESCRIPTION_DEVICE_ME610016; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6114: *device_name = ME6000_NAME_DEVICE_ME6100I4; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I4; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6118: *device_name = ME6000_NAME_DEVICE_ME6100I8; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I8; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME611F: *device_name = ME6000_NAME_DEVICE_ME6100I16; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I16; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6134: *device_name = ME6000_NAME_DEVICE_ME6100ISLE4; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6138: *device_name = ME6000_NAME_DEVICE_ME6100ISLE8; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME613F: *device_name = ME6000_NAME_DEVICE_ME6100ISLE16; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6044: *device_name = ME6000_NAME_DEVICE_ME60004DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME60004DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6048: *device_name = ME6000_NAME_DEVICE_ME60008DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME60008DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME604F: *device_name = ME6000_NAME_DEVICE_ME600016DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME600016DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6054: *device_name = ME6000_NAME_DEVICE_ME6000I4DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I4DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6058: *device_name = ME6000_NAME_DEVICE_ME6000I8DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I8DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME605F: *device_name = ME6000_NAME_DEVICE_ME6000I16DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I16DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6074: *device_name = ME6000_NAME_DEVICE_ME6000ISLE4DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6078: *device_name = ME6000_NAME_DEVICE_ME6000ISLE8DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME607F: *device_name = ME6000_NAME_DEVICE_ME6000ISLE16DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6144: *device_name = ME6000_NAME_DEVICE_ME61004DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME61004DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6148: *device_name = ME6000_NAME_DEVICE_ME61008DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME61008DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME614F: *device_name = ME6000_NAME_DEVICE_ME610016DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME610016DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6154: *device_name = ME6000_NAME_DEVICE_ME6100I4DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I4DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6158: *device_name = ME6000_NAME_DEVICE_ME6100I8DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I8DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME615F: *device_name = ME6000_NAME_DEVICE_ME6100I16DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I16DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6174: *device_name = ME6000_NAME_DEVICE_ME6100ISLE4DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6178: *device_name = ME6000_NAME_DEVICE_ME6100ISLE8DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME617F: *device_name = ME6000_NAME_DEVICE_ME6100ISLE16DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6259: *device_name = ME6000_NAME_DEVICE_ME6200I9DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6200I9DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME6359: *device_name = ME6000_NAME_DEVICE_ME6300I9DIO; *device_description = ME6000_DESCRIPTION_DEVICE_ME6300I9DIO; *driver_name = ME6000_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME0630: *device_name = ME0600_NAME_DEVICE_ME0630; *device_description = ME0600_DESCRIPTION_DEVICE_ME0630; *driver_name = ME0600_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME8100_A: *device_name = ME8100_NAME_DEVICE_ME8100A; *device_description = ME8100_DESCRIPTION_DEVICE_ME8100A; *driver_name = ME8100_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME8100_B: *device_name = ME8100_NAME_DEVICE_ME8100B; *device_description = ME8100_DESCRIPTION_DEVICE_ME8100B; *driver_name = ME8100_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME8200_A: *device_name = ME8200_NAME_DEVICE_ME8200A; *device_description = ME8200_DESCRIPTION_DEVICE_ME8200A; *driver_name = ME8200_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME8200_B: *device_name = ME8200_NAME_DEVICE_ME8200B; *device_description = ME8200_DESCRIPTION_DEVICE_ME8200B; *driver_name = ME8200_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME0940: *device_name = ME0900_NAME_DEVICE_ME0940; *device_description = ME0900_DESCRIPTION_DEVICE_ME0940; *driver_name = ME0900_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME0950: *device_name = ME0900_NAME_DEVICE_ME0950; *device_description = ME0900_DESCRIPTION_DEVICE_ME0950; *driver_name = ME0900_NAME_DRIVER; break; case PCI_DEVICE_ID_MEILHAUS_ME0960: *device_name = ME0900_NAME_DEVICE_ME0960; *device_description = ME0900_DESCRIPTION_DEVICE_ME0960; *driver_name = ME0900_NAME_DRIVER; break; /* case USB_DEVICE_ID_MEPHISTO_S1: *device_name = MEPHISTO_S1_NAME_DEVICE; *device_description = MEPHISTO_S1_DESCRIPTION_DEVICE; *driver_name = MEPHISTO_S1_NAME_DRIVER; break; */ default: *device_name = EMPTY_NAME_DEVICE; *device_description = EMPTY_DESCRIPTION_DEVICE; *driver_name = EMPTY_NAME_DRIVER; PERROR("Invalid device id.\n"); return 1; } return 0; } int me_device_pci_init(me_device_t * me_device, struct pci_dev *pci_device) { int err; int i; PDEBUG("executed.\n"); // Initialize device list head. INIT_LIST_HEAD(&me_device->list); // Initialize device description strings. err = get_device_descriptions(pci_device->device, &me_device->device_name, &me_device->device_description, &me_device->driver_name); if (err) { PERROR("Cannot initialize device description strings.\n"); return 1; } // Enable the pci device. err = pci_enable_device(pci_device); if (err < 0) { PERROR("Cannot enable PCI device.\n"); return 1; } // Request the PCI register regions. err = pci_request_regions(pci_device, me_device->device_name); if (err < 0) { PERROR("Cannot request PCI regions.\n"); goto ERROR_0; } // The bus carrying the device is a PCI bus. me_device->bus_type = ME_BUS_TYPE_PCI; // Store the PCI information for later usage. me_device->info.pci.pci_device = pci_device; // Get PCI register bases and sizes. for (i = 0; i < 6; i++) { me_device->info.pci.reg_bases[i] = pci_resource_start(pci_device, i); me_device->info.pci.reg_sizes[i] = pci_resource_len(pci_device, i); } // Get the PCI location. me_device->info.pci.pci_bus_no = pci_device->bus->number; me_device->info.pci.pci_dev_no = PCI_SLOT(pci_device->devfn); me_device->info.pci.pci_func_no = PCI_FUNC(pci_device->devfn); // Get Meilhaus specific device information. me_device->info.pci.vendor_id = pci_device->vendor; me_device->info.pci.device_id = pci_device->device; pci_read_config_byte(pci_device, 0x08, &me_device->info.pci.hw_revision); pci_read_config_dword(pci_device, 0x2C, &me_device->info.pci.serial_no); // Get the interrupt request number. me_device->irq = pci_device->irq; // Initialize device lock instance. err = me_dlock_init(&me_device->dlock); if (err) { PERROR("Cannot initialize device lock instance.\n"); goto ERROR_1; } // Initialize subdevice list instance. me_slist_init(&me_device->slist); if (err) { PERROR("Cannot initialize subdevice list instance.\n"); goto ERROR_2; } // Initialize method pointers. me_device->me_device_io_irq_start = me_device_io_irq_start; me_device->me_device_io_irq_wait = me_device_io_irq_wait; me_device->me_device_io_irq_stop = me_device_io_irq_stop; me_device->me_device_io_reset_device = me_device_io_reset_device; me_device->me_device_io_reset_subdevice = me_device_io_reset_subdevice; me_device->me_device_io_single_config = me_device_io_single_config; me_device->me_device_io_single_read = me_device_io_single_read; me_device->me_device_io_single_write = me_device_io_single_write; me_device->me_device_io_stream_config = me_device_io_stream_config; me_device->me_device_io_stream_new_values = me_device_io_stream_new_values; me_device->me_device_io_stream_read = me_device_io_stream_read; me_device->me_device_io_stream_start = me_device_io_stream_start; me_device->me_device_io_stream_status = me_device_io_stream_status; me_device->me_device_io_stream_stop = me_device_io_stream_stop; me_device->me_device_io_stream_write = me_device_io_stream_write; me_device->me_device_lock_device = me_device_lock_device; me_device->me_device_lock_subdevice = me_device_lock_subdevice; me_device->me_device_query_description_device = me_device_query_description_device; me_device->me_device_query_info_device = me_device_query_info_device; me_device->me_device_query_name_device = me_device_query_name_device; me_device->me_device_query_name_device_driver = me_device_query_name_device_driver; me_device->me_device_query_number_subdevices = me_device_query_number_subdevices; me_device->me_device_query_number_channels = me_device_query_number_channels; me_device->me_device_query_number_ranges = me_device_query_number_ranges; me_device->me_device_query_range_by_min_max = me_device_query_range_by_min_max; me_device->me_device_query_range_info = me_device_query_range_info; me_device->me_device_query_subdevice_by_type = me_device_query_subdevice_by_type; me_device->me_device_query_subdevice_type = me_device_query_subdevice_type; me_device->me_device_query_subdevice_caps = me_device_query_subdevice_caps; me_device->me_device_query_subdevice_caps_args = me_device_query_subdevice_caps_args; me_device->me_device_query_timer = me_device_query_timer; me_device->me_device_query_version_device_driver = me_device_query_version_device_driver; me_device->me_device_config_load = me_device_config_load; me_device->me_device_destructor = me_device_destructor; return 0; ERROR_0: me_dlock_deinit(&me_device->dlock); ERROR_1: pci_release_regions(pci_device); ERROR_2: pci_disable_device(pci_device); return 1; } void me_device_deinit(me_device_t * me_device) { PDEBUG("executed.\n"); me_slist_deinit(&me_device->slist); me_dlock_deinit(&me_device->dlock); if (me_device->bus_type == ME_BUS_TYPE_PCI) { pci_release_regions(me_device->info.pci.pci_device); pci_disable_device(me_device->info.pci.pci_device); } /* else { // Must be an USB device. } */ }