342 lines
8.6 KiB
C
342 lines
8.6 KiB
C
/******************************************************************************
|
|
*
|
|
* 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 <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
|
|
#include "master.h"
|
|
#include "device.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
int __init ec_init_module(void);
|
|
void __exit ec_cleanup_module(void);
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define EC_LIT(X) #X
|
|
#define EC_STR(X) EC_LIT(X)
|
|
|
|
#define COMPILE_INFO "Revision " EC_STR(EC_REV) \
|
|
", compiled by " EC_STR(EC_USER) \
|
|
" at " EC_STR(EC_DATE)
|
|
|
|
/*****************************************************************************/
|
|
|
|
int ec_master_count = 1;
|
|
ec_master_t *ec_masters = NULL;
|
|
int *ec_masters_reserved = NULL;
|
|
|
|
/*****************************************************************************/
|
|
|
|
MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
|
|
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;
|
|
|
|
EC_INFO("Master driver, %s\n", COMPILE_INFO);
|
|
|
|
if (ec_master_count < 1) {
|
|
EC_ERR("Error - Illegal ec_master_count: %i\n", ec_master_count);
|
|
return -1;
|
|
}
|
|
|
|
EC_INFO("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) {
|
|
EC_ERR("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) {
|
|
EC_ERR("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;
|
|
}
|
|
|
|
EC_INFO("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;
|
|
|
|
EC_INFO("Cleaning up master driver...\n");
|
|
|
|
if (ec_masters) {
|
|
for (i = 0; i < ec_master_count; i++) {
|
|
if (ec_masters_reserved[i]) {
|
|
EC_WARN("Master %i is still in use!\n", i);
|
|
}
|
|
ec_master_clear(&ec_masters[i]);
|
|
}
|
|
kfree(ec_masters);
|
|
}
|
|
|
|
EC_INFO("Master driver cleaned up.\n");
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Treiberschnittstelle
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
Registeriert das EtherCAT-Geraet fuer einen EtherCAT-Master.
|
|
|
|
@param master_index Index des EtherCAT-Masters
|
|
@param dev Das net_device des EtherCAT-Geraetes
|
|
@param isr Funktionszeiger auf die Interrupt-Service-Routine
|
|
@param module Zeiger auf das Modul (fuer try_module_lock())
|
|
|
|
@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;
|
|
ec_master_t *master;
|
|
|
|
if (master_index >= ec_master_count) {
|
|
EC_ERR("Master %i does not exist!\n", master_index);
|
|
return NULL;
|
|
}
|
|
|
|
if (!dev) {
|
|
EC_WARN("Device is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
master = ec_masters + master_index;
|
|
|
|
if (master->device_registered) {
|
|
EC_ERR("Master %i already has a device!\n", master_index);
|
|
return NULL;
|
|
}
|
|
|
|
ecd = &master->device;
|
|
|
|
if (ec_device_init(ecd, master) < 0) return NULL;
|
|
|
|
ecd->dev = dev;
|
|
ecd->tx_skb->dev = dev;
|
|
ecd->isr = isr;
|
|
ecd->module = module;
|
|
|
|
master->device_registered = 1;
|
|
|
|
return ecd;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
Entfernt das EtherCAT-Geraet eines EtherCAT-Masters.
|
|
|
|
@param master_index Der Index des EtherCAT-Masters
|
|
@param ecd Das EtherCAT-Geraet
|
|
*/
|
|
|
|
void EtherCAT_dev_unregister(unsigned int master_index, ec_device_t *ecd)
|
|
{
|
|
ec_master_t *master;
|
|
|
|
if (master_index >= ec_master_count) {
|
|
EC_WARN("Master %i does not exist!\n", master_index);
|
|
return;
|
|
}
|
|
|
|
master = ec_masters + master_index;
|
|
|
|
if (!master->device_registered || &master->device != ecd) {
|
|
EC_WARN("Unable to unregister device!\n");
|
|
return;
|
|
}
|
|
|
|
master->device_registered = 0;
|
|
ec_device_clear(ecd);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* 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(unsigned int index)
|
|
{
|
|
ec_master_t *master;
|
|
|
|
if (index < 0 || index >= ec_master_count) {
|
|
EC_ERR("Master %i does not exist!\n", index);
|
|
goto req_return;
|
|
}
|
|
|
|
if (ec_masters_reserved[index]) {
|
|
EC_ERR("Master %i already in use!\n", index);
|
|
goto req_return;
|
|
}
|
|
|
|
master = &ec_masters[index];
|
|
|
|
if (!master->device_registered) {
|
|
EC_ERR("Master %i has no device assigned yet!\n", index);
|
|
goto req_return;
|
|
}
|
|
|
|
if (!try_module_get(master->device.module)) {
|
|
EC_ERR("Failed to reserve device module!\n");
|
|
goto req_return;
|
|
}
|
|
|
|
if (ec_master_open(master) < 0) {
|
|
EC_ERR("Failed to open device!\n");
|
|
goto req_module_put;
|
|
}
|
|
|
|
if (ec_scan_for_slaves(master) != 0) {
|
|
EC_ERR("Bus scan failed!\n");
|
|
goto req_close;
|
|
}
|
|
|
|
ec_masters_reserved[index] = 1;
|
|
EC_INFO("Reserved master %i.\n", index);
|
|
|
|
return master;
|
|
|
|
req_close:
|
|
ec_master_close(master);
|
|
|
|
req_module_put:
|
|
module_put(master->device.module);
|
|
ec_master_reset(master);
|
|
|
|
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) {
|
|
EC_WARN("Failed to release device module: No device!\n");
|
|
return;
|
|
}
|
|
|
|
ec_master_close(master);
|
|
ec_master_reset(master);
|
|
|
|
module_put(master->device.module);
|
|
ec_masters_reserved[i] = 0;
|
|
|
|
EC_INFO("Released master %i.\n", i);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
EC_WARN("Master %X was never requested!\n", (u32) 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);
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Emacs-Konfiguration
|
|
;;; Local Variables: ***
|
|
;;; c-basic-offset:4 ***
|
|
;;; End: ***
|
|
*/
|