diff -r 6b3b8acb71b5 -r 7506e67dd122 master/module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/module.c Tue Jan 17 18:28:15 2006 +0000 @@ -0,0 +1,336 @@ +/****************************************************************************** + * + * m o d u l e . c + * + * EtherCAT-Master-Treiber + * + * Autoren: Wilhelm Hagemeister, Florian Pose + * + * $Id$ + * + * (C) Copyright IgH 2005 + * Ingenieurgemeinschaft IgH + * Heinz-Bäcker Str. 34 + * D-45356 Essen + * Tel.: +49 201/61 99 31 + * Fax.: +49 201/61 98 36 + * E-mail: sp@igh-essen.com + * + *****************************************************************************/ + +#include +#include +#include + +#include "master.h" +#include "device.h" + +/*****************************************************************************/ + +int __init ec_init_module(void); +void __exit ec_cleanup_module(void); + +/*****************************************************************************/ + +#define LIT(X) #X +#define STR(X) LIT(X) + +#define COMPILE_INFO "Revision " STR(EC_REV) \ + ", compiled by " STR(EC_USER) \ + " at " STR(EC_DATE) + +/*****************************************************************************/ + +int ec_master_count = 1; +ec_master_t *ec_masters = NULL; +int *ec_masters_reserved = NULL; + +/*****************************************************************************/ + +MODULE_AUTHOR ("Wilhelm Hagemeister ," + "Florian Pose "); +MODULE_DESCRIPTION ("EtherCAT master driver module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(COMPILE_INFO); + +module_param(ec_master_count, int, 1); +MODULE_PARM_DESC(ec_master_count, "Number of EtherCAT master to initialize."); + +/*****************************************************************************/ + +/** + Init-Funktion des EtherCAT-Master-Treibermodules + + Initialisiert soviele Master, wie im Parameter ec_master_count + angegeben wurde (Default ist 1). + + @returns 0, wenn alles o.k., -1 bei ungueltiger Anzahl Master + oder zu wenig Speicher. +*/ + +int __init ec_init_module(void) +{ + unsigned int i; + + printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO); + + if (ec_master_count < 1) { + printk(KERN_ERR "EtherCAT: Error - Illegal" + " ec_master_count: %i\n", ec_master_count); + return -1; + } + + printk(KERN_ERR "EtherCAT: Initializing %i EtherCAT master(s)...\n", + ec_master_count); + + if ((ec_masters = + (ec_master_t *) kmalloc(sizeof(ec_master_t) + * ec_master_count, + GFP_KERNEL)) == NULL) { + printk(KERN_ERR "EtherCAT: Could not allocate" + " memory for EtherCAT master(s)!\n"); + return -1; + } + + if ((ec_masters_reserved = + (int *) kmalloc(sizeof(int) * ec_master_count, + GFP_KERNEL)) == NULL) { + printk(KERN_ERR "EtherCAT: Could not allocate" + " memory for reservation flags!\n"); + kfree(ec_masters); + return -1; + } + + for (i = 0; i < ec_master_count; i++) + { + ec_master_init(&ec_masters[i]); + ec_masters_reserved[i] = 0; + } + + printk(KERN_ERR "EtherCAT: Master driver initialized.\n"); + + return 0; +} + +/*****************************************************************************/ + +/** + Cleanup-Funktion des EtherCAT-Master-Treibermoduls + + Entfernt alle Master-Instanzen. +*/ + +void __exit ec_cleanup_module(void) +{ + unsigned int i; + + printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n"); + + if (ec_masters) + { + for (i = 0; i < ec_master_count; i++) + { + if (ec_masters_reserved[i]) { + printk(KERN_WARNING "EtherCAT: Warning -" + " Master %i is still in use!\n", i); + } + + ec_master_clear(&ec_masters[i]); + } + + kfree(ec_masters); + } + + printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n"); +} + +/****************************************************************************** + * + * Treiberschnittstelle + * + *****************************************************************************/ + +/** + Setzt das EtherCAT-Geraet, auf dem der Master arbeitet. + + + @param master Der EtherCAT-Master + @param device Das EtherCAT-Geraet + @return 0, wenn alles o.k., + < 0, wenn bereits ein Geraet registriert + oder das Geraet nicht geoeffnet werden konnte. +*/ + +ec_device_t *EtherCAT_dev_register(unsigned int master_index, + struct net_device *dev, + irqreturn_t (*isr)(int, void *, + struct pt_regs *), + struct module *module) +{ + ec_device_t *ecd; + + if (master_index >= ec_master_count) { + printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", master_index); + return NULL; + } + + if (!dev) { + printk("EtherCAT: Device is NULL!\n"); + return NULL; + } + + if (ec_masters[master_index].device_registered) { + printk(KERN_ERR "EtherCAT: Master %i already has a device!\n", + master_index); + return NULL; + } + + ecd = &ec_masters[master_index].device; + + if (ec_device_init(ecd) < 0) { + return NULL; + } + + ecd->dev = dev; + ecd->tx_skb->dev = dev; + ecd->rx_skb->dev = dev; + ecd->isr = isr; + ecd->module = module; + + return ecd; +} + +/*****************************************************************************/ + +/** + Loescht das EtherCAT-Geraet, auf dem der Master arbeitet. + + @param master Der EtherCAT-Master + @param device Das EtherCAT-Geraet +*/ + +void EtherCAT_dev_unregister(unsigned int master_index) +{ + if (master_index >= ec_master_count) { + printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", master_index); + return; + } + + ec_masters[master_index].device_registered = 0; + ec_device_clear(&ec_masters[master_index].device); +} + +/****************************************************************************** + * + * Echtzeitschnittstelle + * + *****************************************************************************/ + +/** + Reserviert einen bestimmten EtherCAT-Master und das zugehörige Gerät. + + Gibt einen Zeiger auf den reservierten EtherCAT-Master zurueck. + + @param index Index des gewuenschten Masters + @returns Zeiger auf EtherCAT-Master oder NULL, wenn Parameter ungueltig. +*/ + +ec_master_t *EtherCAT_rt_request_master(int index) +{ + ec_master_t *master; + + if (index < 0 || index >= ec_master_count) { + printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index); + goto req_return; + } + + if (ec_masters_reserved[index]) { + printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index); + goto req_return; + } + + master = &ec_masters[index]; + + if (!master->device_registered) { + printk(KERN_ERR "EtherCAT: Master %i has no device assigned yet!\n", + index); + goto req_return; + } + + if (!try_module_get(master->device.module)) { + printk(KERN_ERR "EtherCAT: Could not reserve device module!\n"); + goto req_return; + } + + if (ec_master_open(master) < 0) { + printk(KERN_ERR "EtherCAT: Could not open device!\n"); + goto req_module_put; + } + + if (ec_scan_for_slaves(master) != 0) { + printk(KERN_ERR "EtherCAT: Could not scan for slaves!\n"); + goto req_close; + } + + ec_masters_reserved[index] = 1; + printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index); + + return master; + + req_close: + ec_master_close(master); + + req_module_put: + module_put(master->device.module); + + req_return: + return NULL; +} + +/*****************************************************************************/ + +/** + Gibt einen zuvor angeforderten EtherCAT-Master wieder frei. + + @param master Zeiger auf den freizugebenden EtherCAT-Master. +*/ + +void EtherCAT_rt_release_master(ec_master_t *master) +{ + unsigned int i; + + for (i = 0; i < ec_master_count; i++) + { + if (&ec_masters[i] == master) + { + if (!master->device_registered) { + printk(KERN_WARNING "EtherCAT: Could not release device" + "module because of no device!\n"); + return; + } + + ec_master_close(master); + module_put(master->device.module); + ec_masters_reserved[i] = 0; + + printk(KERN_INFO "EtherCAT: Released master %i.\n", i); + + return; + } + } + + printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n", + (unsigned int) master); +} + +/*****************************************************************************/ + +module_init(ec_init_module); +module_exit(ec_cleanup_module); + +EXPORT_SYMBOL(EtherCAT_dev_register); +EXPORT_SYMBOL(EtherCAT_dev_unregister); +EXPORT_SYMBOL(EtherCAT_rt_request_master); +EXPORT_SYMBOL(EtherCAT_rt_release_master); + +/*****************************************************************************/