Skip to content
Snippets Groups Projects
Commit 4375e328 authored by Florian Pose's avatar Florian Pose
Browse files

Layed out device ID functionality in own files.

parent 69a014d8
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
/******************************************************************************
*
* $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;
}
}
/*****************************************************************************/
/******************************************************************************
*
* $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"
......
......@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment