Layed out device ID functionality in own files.
This commit is contained in:
parent
afd188c829
commit
383a1f7631
|
|
@ -35,10 +35,9 @@ include $(src)/../config.kbuild
|
|||
|
||||
obj-m := ec_master.o
|
||||
|
||||
ec_master-objs := module.o master.o device.o slave.o datagram.o \
|
||||
domain.o mailbox.o canopen.o ethernet.o \
|
||||
fsm_sii.o fsm_change.o fsm_coe.o fsm_slave.o fsm_master.o \
|
||||
xmldev.o
|
||||
ec_master-objs := module.o master.o device.o device_id.o slave.o datagram.o \
|
||||
domain.o mailbox.o canopen.o ethernet.o fsm_sii.o fsm_change.o fsm_coe.o \
|
||||
fsm_slave.o fsm_master.o xmldev.o
|
||||
|
||||
ifeq ($(EC_DBG_IF),1)
|
||||
ec_master-objs += debug.o
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ EXTRA_DIST = \
|
|||
datagram.c datagram.h \
|
||||
debug.c debug.h \
|
||||
device.c device.h \
|
||||
device_id.c device_id.h \
|
||||
domain.c domain.h \
|
||||
doxygen.c \
|
||||
ethernet.c ethernet.h \
|
||||
|
|
|
|||
|
|
@ -53,21 +53,6 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
ec_device_id_empty,
|
||||
ec_device_id_mac
|
||||
}
|
||||
ec_device_id_type_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
ec_device_id_type_t type;
|
||||
unsigned char octets[ETH_ALEN];
|
||||
}
|
||||
ec_device_id_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT device.
|
||||
An EtherCAT device is a network interface card, that is owned by an
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master 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.
|
||||
*
|
||||
* The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT device ID.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "device_id.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int ec_device_id_parse_mac(ec_device_id_t *dev_id,
|
||||
const char *src, const char **remainder)
|
||||
{
|
||||
unsigned int i, value;
|
||||
char *rem;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
value = simple_strtoul(src, &rem, 16);
|
||||
if (rem != src + 2
|
||||
|| value > 0xFF
|
||||
|| (i < ETH_ALEN - 1 && *rem != ':')) {
|
||||
return -1;
|
||||
}
|
||||
dev_id->octets[i] = value;
|
||||
if (i < ETH_ALEN - 1)
|
||||
src = rem + 1;
|
||||
}
|
||||
|
||||
dev_id->type = ec_device_id_mac;
|
||||
*remainder = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_device_id_clear_list(struct list_head *ids)
|
||||
{
|
||||
ec_device_id_t *dev_id, *next_dev_id;
|
||||
|
||||
list_for_each_entry_safe(dev_id, next_dev_id, ids, list) {
|
||||
list_del(&dev_id->list);
|
||||
kfree(dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int ec_device_id_create_list(struct list_head *ids, const char *src)
|
||||
{
|
||||
const char *rem;
|
||||
ec_device_id_t *dev_id;
|
||||
unsigned int index = 0;
|
||||
|
||||
while (*src) {
|
||||
// allocate new device ID
|
||||
if (!(dev_id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (*src == ';') { // empty device ID
|
||||
dev_id->type = ec_device_id_empty;
|
||||
}
|
||||
else if (*src == 'M') {
|
||||
src++;
|
||||
if (ec_device_id_parse_mac(dev_id, src, &rem)) {
|
||||
EC_ERR("Device ID %u: Invalid MAC syntax!\n", index);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
src = rem;
|
||||
}
|
||||
else {
|
||||
EC_ERR("Device ID %u: Unknown format \'%c\'!\n", index, *src);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list_add_tail(&dev_id->list, ids);
|
||||
|
||||
if (*src) {
|
||||
if (*src != ';') {
|
||||
EC_ERR("Invalid delimiter '%c' after device ID %i!\n",
|
||||
*src, index);
|
||||
goto out_free;
|
||||
}
|
||||
src++; // skip delimiter
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
ec_device_id_clear_list(ids);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_process_params(const char *main, const char *backup,
|
||||
struct list_head *main_ids, struct list_head *backup_ids)
|
||||
{
|
||||
ec_device_id_t *id;
|
||||
unsigned int main_count = 0, backup_count = 0;
|
||||
|
||||
if (ec_device_id_create_list(main_ids, main))
|
||||
return -1;
|
||||
|
||||
if (ec_device_id_create_list(backup_ids, backup))
|
||||
return -1;
|
||||
|
||||
// count main device IDs and check for empty ones
|
||||
list_for_each_entry(id, main_ids, list) {
|
||||
if (id->type == ec_device_id_empty) {
|
||||
EC_ERR("Main device IDs may not be empty!\n");
|
||||
return -1;
|
||||
}
|
||||
main_count++;
|
||||
}
|
||||
|
||||
// count backup device IDs
|
||||
list_for_each_entry(id, backup_ids, list) {
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
// fill up backup device IDs
|
||||
while (backup_count < main_count) {
|
||||
if (!(id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
id->type = ec_device_id_empty;
|
||||
list_add_tail(&id->list, backup_ids);
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_check(const ec_device_id_t *dev_id,
|
||||
const struct net_device *dev, const char *driver_name,
|
||||
unsigned int device_index)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (dev_id->type) {
|
||||
case ec_device_id_mac:
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (dev->dev_addr[i] != dev_id->octets[i])
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master 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.
|
||||
*
|
||||
* The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT device ID structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_DEVICE_ID_H_
|
||||
#define _EC_DEVICE_ID_H_
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
ec_device_id_empty,
|
||||
ec_device_id_mac
|
||||
}
|
||||
ec_device_id_type_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
ec_device_id_type_t type;
|
||||
unsigned char octets[ETH_ALEN];
|
||||
}
|
||||
ec_device_id_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_process_params(const char *, const char *,
|
||||
struct list_head *, struct list_head *);
|
||||
void ec_device_id_clear_list(struct list_head *);
|
||||
int ec_device_id_check(const ec_device_id_t *, const struct net_device *,
|
||||
const char *, unsigned int);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -48,6 +48,7 @@
|
|||
#include <asm/semaphore.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_id.h"
|
||||
#include "domain.h"
|
||||
#include "fsm_master.h"
|
||||
|
||||
|
|
|
|||
186
master/module.c
186
master/module.c
|
|
@ -57,8 +57,8 @@ void __exit ec_cleanup_module(void);
|
|||
static char *main; /**< main devices parameter */
|
||||
static char *backup; /**< backup devices parameter */
|
||||
|
||||
static LIST_HEAD(main_device_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(backup_device_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(main_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(backup_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(masters); /**< list of masters */
|
||||
static dev_t device_number; /**< XML character device number */
|
||||
ec_xmldev_t xmldev; /**< XML character device */
|
||||
|
|
@ -81,157 +81,6 @@ MODULE_PARM_DESC(backup, "backup device IDs");
|
|||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void clear_device_ids(struct list_head *device_ids)
|
||||
{
|
||||
ec_device_id_t *dev_id, *next_dev_id;
|
||||
|
||||
list_for_each_entry_safe(dev_id, next_dev_id, device_ids, list) {
|
||||
list_del(&dev_id->list);
|
||||
kfree(dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int parse_device_id_mac(ec_device_id_t *dev_id,
|
||||
const char *src, const char **remainder)
|
||||
{
|
||||
unsigned int i, value;
|
||||
char *rem;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
value = simple_strtoul(src, &rem, 16);
|
||||
if (rem != src + 2
|
||||
|| value > 0xFF
|
||||
|| (i < ETH_ALEN - 1 && *rem != ':')) {
|
||||
return -1;
|
||||
}
|
||||
dev_id->octets[i] = value;
|
||||
if (i < ETH_ALEN - 1)
|
||||
src = rem + 1;
|
||||
}
|
||||
|
||||
dev_id->type = ec_device_id_mac;
|
||||
*remainder = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int parse_device_ids(struct list_head *device_ids, const char *src)
|
||||
{
|
||||
const char *rem;
|
||||
ec_device_id_t *dev_id;
|
||||
unsigned int index = 0;
|
||||
|
||||
while (*src) {
|
||||
// allocate new device ID
|
||||
if (!(dev_id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (*src == ';') { // empty device ID
|
||||
dev_id->type = ec_device_id_empty;
|
||||
}
|
||||
else if (*src == 'M') {
|
||||
src++;
|
||||
if (parse_device_id_mac(dev_id, src, &rem)) {
|
||||
EC_ERR("Device ID %u: Invalid MAC syntax!\n", index);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
src = rem;
|
||||
}
|
||||
else {
|
||||
EC_ERR("Device ID %u: Unknown format \'%c\'!\n", index, *src);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list_add_tail(&dev_id->list, device_ids);
|
||||
if (*src) {
|
||||
if (*src != ';') {
|
||||
EC_ERR("Invalid delimiter '%c' after device ID %i!\n",
|
||||
*src, index);
|
||||
goto out_free;
|
||||
}
|
||||
src++; // skip delimiter
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
clear_device_ids(device_ids);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int create_device_ids(void)
|
||||
{
|
||||
ec_device_id_t *id;
|
||||
unsigned int main_count = 0, backup_count = 0;
|
||||
|
||||
if (parse_device_ids(&main_device_ids, main))
|
||||
return -1;
|
||||
|
||||
if (parse_device_ids(&backup_device_ids, main))
|
||||
return -1;
|
||||
|
||||
// count main device IDs and check for empty ones
|
||||
list_for_each_entry(id, &main_device_ids, list) {
|
||||
if (id->type == ec_device_id_empty) {
|
||||
EC_ERR("Main device IDs may not be empty!\n");
|
||||
return -1;
|
||||
}
|
||||
main_count++;
|
||||
}
|
||||
|
||||
// count backup device IDs
|
||||
list_for_each_entry(id, &backup_device_ids, list) {
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
// fill up backup device IDs
|
||||
while (backup_count < main_count) {
|
||||
if (!(id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
id->type = ec_device_id_empty;
|
||||
list_add_tail(&id->list, &backup_device_ids);
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int device_id_check(const ec_device_id_t *dev_id,
|
||||
const struct net_device *dev, const char *driver_name,
|
||||
unsigned int device_index)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (dev_id->type) {
|
||||
case ec_device_id_mac:
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (dev->dev_addr[i] != dev_id->octets[i])
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
|
|
@ -253,14 +102,16 @@ int __init ec_init_module(void)
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
if (create_device_ids())
|
||||
goto out_free_ids;
|
||||
if (ec_device_id_process_params(main, backup, &main_ids, &backup_ids))
|
||||
goto out_cdev;
|
||||
|
||||
if (!list_empty(&main_device_ids)) {
|
||||
// create as many masters as main device IDs present
|
||||
if (!list_empty(&main_ids)) {
|
||||
// main_ids and backup_ids are of equal size at this point
|
||||
main_dev_id =
|
||||
list_entry(main_device_ids.next, ec_device_id_t, list);
|
||||
list_entry(main_ids.next, ec_device_id_t, list);
|
||||
backup_dev_id =
|
||||
list_entry(backup_device_ids.next, ec_device_id_t, list);
|
||||
list_entry(backup_ids.next, ec_device_id_t, list);
|
||||
|
||||
while (1) {
|
||||
if (!(master = (ec_master_t *)
|
||||
|
|
@ -278,7 +129,7 @@ int __init ec_init_module(void)
|
|||
master_index++;
|
||||
|
||||
// last device IDs?
|
||||
if (main_dev_id->list.next == &main_device_ids)
|
||||
if (main_dev_id->list.next == &main_ids)
|
||||
break;
|
||||
|
||||
// next device IDs
|
||||
|
|
@ -296,12 +147,11 @@ int __init ec_init_module(void)
|
|||
out_free_masters:
|
||||
list_for_each_entry_safe(master, next, &masters, list) {
|
||||
list_del(&master->list);
|
||||
kobject_del(&master->kobj);
|
||||
kobject_put(&master->kobj);
|
||||
ec_master_destroy(master);
|
||||
}
|
||||
out_free_ids:
|
||||
clear_device_ids(&main_device_ids);
|
||||
clear_device_ids(&backup_device_ids);
|
||||
ec_device_id_clear_list(&main_ids);
|
||||
ec_device_id_clear_list(&backup_ids);
|
||||
out_cdev:
|
||||
unregister_chrdev_region(device_number, 1);
|
||||
out_return:
|
||||
return -1;
|
||||
|
|
@ -318,16 +168,18 @@ void __exit ec_cleanup_module(void)
|
|||
{
|
||||
ec_master_t *master, *next;
|
||||
|
||||
EC_INFO("Cleaning up master driver...\n");
|
||||
EC_INFO("Cleaning up master module...\n");
|
||||
|
||||
list_for_each_entry_safe(master, next, &masters, list) {
|
||||
list_del(&master->list);
|
||||
ec_master_destroy(master);
|
||||
}
|
||||
|
||||
ec_device_id_clear_list(&main_ids);
|
||||
ec_device_id_clear_list(&backup_ids);
|
||||
unregister_chrdev_region(device_number, 1);
|
||||
|
||||
EC_INFO("Master driver cleaned up.\n");
|
||||
EC_INFO("Master module cleaned up.\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -474,7 +326,7 @@ int ecdev_offer(struct net_device *net_dev, /**< net_device to offer */
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
if (device_id_check(master->main_device_id, net_dev,
|
||||
if (ec_device_id_check(master->main_device_id, net_dev,
|
||||
driver_name, device_index)) {
|
||||
|
||||
EC_INFO("Accepting device %s:%u (", driver_name, device_index);
|
||||
|
|
|
|||
Loading…
Reference in New Issue