fp@27: /****************************************************************************** fp@27: * fp@54: * m o d u l e . c fp@27: * fp@27: * EtherCAT-Master-Treiber fp@27: * fp@27: * Autoren: Wilhelm Hagemeister, Florian Pose fp@27: * fp@27: * $Id$ fp@27: * fp@27: * (C) Copyright IgH 2005 fp@27: * Ingenieurgemeinschaft IgH fp@27: * Heinz-Bäcker Str. 34 fp@27: * D-45356 Essen fp@27: * Tel.: +49 201/61 99 31 fp@27: * Fax.: +49 201/61 98 36 fp@27: * E-mail: sp@igh-essen.com fp@27: * fp@39: *****************************************************************************/ fp@27: fp@27: #include fp@27: #include fp@27: #include fp@27: fp@184: #include "globals.h" fp@54: #include "master.h" fp@54: #include "device.h" fp@54: fp@54: /*****************************************************************************/ fp@54: fp@54: int __init ec_init_module(void); fp@54: void __exit ec_cleanup_module(void); fp@52: fp@39: /*****************************************************************************/ fp@39: fp@98: #define COMPILE_INFO "Revision " EC_STR(SVNREV) \ fp@98: ", compiled by " EC_STR(USER) \ fp@98: " at " __DATE__ " " __TIME__ fp@39: fp@39: /*****************************************************************************/ fp@27: fp@178: static int ec_master_count = 1; fp@178: static struct list_head ec_masters; fp@27: fp@39: /*****************************************************************************/ fp@39: fp@64: MODULE_AUTHOR ("Florian Pose "); fp@27: MODULE_DESCRIPTION ("EtherCAT master driver module"); fp@27: MODULE_LICENSE("GPL"); fp@34: MODULE_VERSION(COMPILE_INFO); fp@27: fp@54: module_param(ec_master_count, int, 1); fp@54: MODULE_PARM_DESC(ec_master_count, "Number of EtherCAT master to initialize."); fp@27: fp@39: /*****************************************************************************/ fp@27: fp@27: /** fp@27: Init-Funktion des EtherCAT-Master-Treibermodules fp@27: fp@54: Initialisiert soviele Master, wie im Parameter ec_master_count fp@27: angegeben wurde (Default ist 1). fp@27: fp@91: \return 0 wenn alles ok, < 0 bei ungültiger Anzahl Master fp@91: oder zu wenig Speicher. fp@54: */ fp@54: fp@54: int __init ec_init_module(void) fp@27: { fp@73: unsigned int i; fp@178: ec_master_t *master, *next; fp@73: fp@84: EC_INFO("Master driver, %s\n", COMPILE_INFO); fp@73: fp@73: if (ec_master_count < 1) { fp@111: EC_ERR("Error - Invalid ec_master_count: %i\n", ec_master_count); fp@127: goto out_return; fp@73: } fp@73: fp@84: EC_INFO("Initializing %i EtherCAT master(s)...\n", ec_master_count); fp@84: fp@178: INIT_LIST_HEAD(&ec_masters); fp@73: fp@73: for (i = 0; i < ec_master_count; i++) { fp@178: if (!(master = fp@178: (ec_master_t *) kmalloc(sizeof(ec_master_t), GFP_KERNEL))) { fp@178: EC_ERR("Failed to allocate memory for EtherCAT master %i.\n", i); fp@178: goto out_free; fp@178: } fp@178: fp@178: if (ec_master_init(master, i)) // kobject_put is done inside... fp@178: goto out_free; fp@178: fp@178: if (kobject_add(&master->kobj)) { fp@178: EC_ERR("Failed to add kobj.\n"); fp@178: kobject_put(&master->kobj); // free master fp@178: goto out_free; fp@178: } fp@178: fp@178: list_add_tail(&master->list, &ec_masters); fp@73: } fp@73: fp@84: EC_INFO("Master driver initialized.\n"); fp@73: return 0; fp@127: fp@178: out_free: fp@178: list_for_each_entry_safe(master, next, &ec_masters, list) { fp@178: list_del(&master->list); fp@178: kobject_del(&master->kobj); fp@178: kobject_put(&master->kobj); fp@178: } fp@127: out_return: fp@127: return -1; fp@27: } fp@27: fp@39: /*****************************************************************************/ fp@27: fp@27: /** fp@27: Cleanup-Funktion des EtherCAT-Master-Treibermoduls fp@27: fp@27: Entfernt alle Master-Instanzen. fp@27: */ fp@27: fp@54: void __exit ec_cleanup_module(void) fp@27: { fp@178: ec_master_t *master, *next; fp@73: fp@84: EC_INFO("Cleaning up master driver...\n"); fp@73: fp@178: list_for_each_entry_safe(master, next, &ec_masters, list) { fp@178: list_del(&master->list); fp@178: kobject_del(&master->kobj); fp@178: kobject_put(&master->kobj); // free master fp@178: } fp@73: fp@84: EC_INFO("Master driver cleaned up.\n"); fp@27: } fp@27: fp@178: /*****************************************************************************/ fp@178: fp@178: /** fp@178: Gets a handle to a certain master. fp@178: \returns pointer to master fp@178: */ fp@178: fp@178: ec_master_t *ec_find_master(unsigned int master_index) fp@178: { fp@178: ec_master_t *master; fp@178: fp@178: list_for_each_entry(master, &ec_masters, list) { fp@178: if (master->index == master_index) return master; fp@178: } fp@178: fp@178: EC_ERR("Master %i does not exist!\n", master_index); fp@178: return NULL; fp@178: } fp@178: fp@54: /****************************************************************************** fp@54: * fp@54: * Treiberschnittstelle fp@54: * fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@58: Registeriert das EtherCAT-Geraet fuer einen EtherCAT-Master. fp@58: fp@91: \return 0 wenn alles ok, oder < 0 wenn bereits ein Gerät registriert fp@91: oder das Geraet nicht geöffnet werden konnte. fp@54: */ fp@54: fp@104: ec_device_t *ecdev_register(unsigned int master_index, fp@104: /**< Index des EtherCAT-Masters */ fp@104: struct net_device *net_dev, fp@104: /**< net_device des EtherCAT-Gerätes */ fp@104: ec_isr_t isr, fp@104: /**< Interrupt-Service-Routine */ fp@104: struct module *module fp@104: /**< Zeiger auf das Modul */ fp@104: ) fp@91: { fp@73: ec_master_t *master; fp@73: fp@98: if (!net_dev) { fp@98: EC_WARN("Device is NULL!\n"); fp@98: return NULL; fp@98: } fp@98: fp@178: if (!(master = ec_find_master(master_index))) return NULL; fp@178: fp@178: // critical section start fp@98: if (master->device) { fp@84: EC_ERR("Master %i already has a device!\n", master_index); fp@73: return NULL; fp@73: } fp@73: fp@178: if (!(master->device = fp@178: (ec_device_t *) kmalloc(sizeof(ec_device_t), GFP_KERNEL))) { fp@161: EC_ERR("Failed to allocate device!\n"); fp@98: return NULL; fp@98: } fp@178: // critical section end fp@98: fp@127: if (ec_device_init(master->device, master, net_dev, isr, module)) { fp@127: kfree(master->device); fp@127: master->device = NULL; fp@127: return NULL; fp@127: } fp@98: fp@98: return master->device; fp@91: } fp@91: fp@91: /*****************************************************************************/ fp@91: fp@91: /** fp@91: Hebt die Registrierung eines EtherCAT-Gerätes auf. fp@91: */ fp@91: fp@104: void ecdev_unregister(unsigned int master_index, fp@104: /**< Index des EtherCAT-Masters */ fp@104: ec_device_t *device fp@104: /**< EtherCAT-Geraet */ fp@104: ) fp@55: { fp@73: ec_master_t *master; fp@73: fp@73: if (master_index >= ec_master_count) { fp@84: EC_WARN("Master %i does not exist!\n", master_index); fp@73: return; fp@73: } fp@73: fp@178: if (!(master = ec_find_master(master_index))) return; fp@73: fp@98: if (!master->device || master->device != device) { fp@84: EC_WARN("Unable to unregister device!\n"); fp@73: return; fp@73: } fp@73: fp@98: ec_device_clear(master->device); fp@98: kfree(master->device); fp@98: master->device = NULL; fp@54: } fp@54: fp@54: /****************************************************************************** fp@54: * fp@54: * Echtzeitschnittstelle fp@54: * fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@33: Reserviert einen bestimmten EtherCAT-Master und das zugehörige Gerät. fp@33: fp@33: Gibt einen Zeiger auf den reservierten EtherCAT-Master zurueck. fp@27: fp@91: \return Zeiger auf EtherCAT-Master oder NULL, wenn Parameter ungueltig. fp@91: */ fp@91: fp@178: ec_master_t *ecrt_request_master(unsigned int master_index fp@104: /**< EtherCAT-Master-Index */ fp@104: ) fp@54: { fp@73: ec_master_t *master; fp@73: fp@178: EC_INFO("Requesting master %i...\n", master_index); fp@178: fp@178: if (!(master = ec_find_master(master_index))) goto req_return; fp@178: fp@178: // begin critical section fp@178: if (master->reserved) { fp@178: EC_ERR("Master %i is already in use!\n", master_index); fp@73: goto req_return; fp@73: } fp@178: master->reserved = 1; fp@178: // end critical section fp@73: fp@98: if (!master->device) { fp@178: EC_ERR("Master %i has no assigned device!\n", master_index); fp@151: goto req_release; fp@73: } fp@73: fp@98: if (!try_module_get(master->device->module)) { fp@84: EC_ERR("Failed to reserve device module!\n"); fp@151: goto req_release; fp@151: } fp@151: fp@151: if (ec_device_open(master->device)) { fp@84: EC_ERR("Failed to open device!\n"); fp@73: goto req_module_put; fp@73: } fp@73: fp@178: if (!master->device->link_state) EC_WARN("Link is DOWN.\n"); fp@178: fp@178: if (ec_master_bus_scan(master)) { fp@84: EC_ERR("Bus scan failed!\n"); fp@73: goto req_close; fp@73: } fp@73: fp@178: EC_INFO("Master %i is ready.\n", master_index); fp@73: return master; fp@54: fp@54: req_close: fp@151: if (ec_device_close(master->device)) fp@151: EC_WARN("Warning - Failed to close device!\n"); fp@54: req_module_put: fp@98: module_put(master->device->module); fp@85: ec_master_reset(master); fp@151: req_release: fp@178: master->reserved = 0; fp@54: req_return: fp@178: EC_ERR("Failed requesting master %i.\n", master_index); fp@73: return NULL; fp@27: } fp@27: fp@39: /*****************************************************************************/ fp@33: fp@33: /** fp@42: Gibt einen zuvor angeforderten EtherCAT-Master wieder frei. fp@91: */ fp@91: fp@151: void ecrt_release_master(ec_master_t *master /**< EtherCAT-Master */) fp@33: { fp@178: EC_INFO("Releasing master %i...\n", master->index); fp@178: fp@178: if (!master->reserved) { fp@178: EC_ERR("Master %i was never requested!\n", master->index); fp@88: return; fp@88: } fp@88: fp@88: ec_master_reset(master); fp@88: fp@151: if (ec_device_close(master->device)) fp@151: EC_WARN("Warning - Failed to close device!\n"); fp@151: fp@98: module_put(master->device->module); fp@178: master->reserved = 0; fp@178: fp@178: EC_INFO("Released master %i.\n", master->index); fp@88: return; fp@33: } fp@33: fp@39: /*****************************************************************************/ fp@54: fp@152: /** fp@152: Gibt Frame-Inhalte zwecks Debugging aus. fp@152: */ fp@152: fp@152: void ec_print_data(const uint8_t *data, size_t size) fp@152: { fp@152: unsigned int i; fp@152: fp@152: EC_DBG(""); fp@152: for (i = 0; i < size; i++) { fp@152: printk("%02X ", data[i]); fp@152: if ((i + 1) % 16 == 0) { fp@152: printk("\n"); fp@152: EC_DBG(""); fp@152: } fp@152: } fp@152: printk("\n"); fp@152: } fp@152: fp@152: /*****************************************************************************/ fp@152: fp@152: /** fp@152: Gibt Frame-Inhalte zwecks Debugging aus, differentiell. fp@152: */ fp@152: fp@152: void ec_print_data_diff(const uint8_t *d1, /**< Daten 1 */ fp@152: const uint8_t *d2, /**< Daten 2 */ fp@152: size_t size /** Anzahl Bytes */ fp@152: ) fp@152: { fp@152: unsigned int i; fp@152: fp@152: EC_DBG(""); fp@152: for (i = 0; i < size; i++) { fp@152: if (d1[i] == d2[i]) printk(".. "); fp@152: else printk("%02X ", d2[i]); fp@152: if ((i + 1) % 16 == 0) { fp@152: printk("\n"); fp@152: EC_DBG(""); fp@152: } fp@152: } fp@152: printk("\n"); fp@152: } fp@152: fp@152: /*****************************************************************************/ fp@152: fp@54: module_init(ec_init_module); fp@54: module_exit(ec_cleanup_module); fp@54: fp@104: EXPORT_SYMBOL(ecdev_register); fp@104: EXPORT_SYMBOL(ecdev_unregister); fp@104: EXPORT_SYMBOL(ecrt_request_master); fp@104: EXPORT_SYMBOL(ecrt_release_master); fp@54: fp@54: /*****************************************************************************/ fp@55: fp@55: /* Emacs-Konfiguration fp@55: ;;; Local Variables: *** fp@73: ;;; c-basic-offset:4 *** fp@55: ;;; End: *** fp@55: */