Layed out device ID functionality in own files.

This commit is contained in:
Florian Pose 2007-02-20 09:43:23 +00:00
parent afd188c829
commit 383a1f7631
7 changed files with 296 additions and 186 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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

199
master/device_id.c Normal file
View File

@ -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;
}
}
/*****************************************************************************/

73
master/device_id.h Normal file
View File

@ -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

View File

@ -48,6 +48,7 @@
#include <asm/semaphore.h>
#include "device.h"
#include "device_id.h"
#include "domain.h"
#include "fsm_master.h"

View File

@ -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);