Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (235 commits)
  Staging: IIO: add selection of IIO_SW_RING to LIS3L02DQ as needed
  Staging: IIO: Add tsl2560-2 support to tsl2563 driver.
  Staging: IIO: Remove tsl2561 driver. Support merged with tsl2563.
  Staging: wlags49_h2: fix up signal levels
  + drivers-staging-wlags49_h2-remove-cvs-metadata.patch added to -mm tree
  Staging: samsung-laptop: add TODO file
  Staging: samsung-laptop: remove old kernel code
  Staging: add Samsung Laptop driver
  staging: batman-adv meshing protocol
  Staging: rtl8192u: depends on USB
  Staging: rtl8192u: remove dead code
  Staging: rtl8192u: remove bad whitespaces
  Staging: rtl8192u: make it compile
  Staging: Added Realtek rtl8192u driver to staging
  Staging: dream: add gpio and pmem support
  Staging: dream: add TODO file
  Staging: android: delete android drivers
  Staging: et131x: clean up the avail fields in the rx registers
  Staging: et131x: Clean up number fields
  Staging: et131x: kill RX_DMA_MAX_PKT_TIME
  ...
This commit is contained in:
Linus Torvalds 2009-12-11 15:25:56 -08:00
commit 0e2f7b8376
679 changed files with 165008 additions and 173796 deletions

View File

@ -65,8 +65,6 @@ source "drivers/staging/rt2860/Kconfig"
source "drivers/staging/rt2870/Kconfig"
source "drivers/staging/rt3090/Kconfig"
source "drivers/staging/comedi/Kconfig"
source "drivers/staging/asus_oled/Kconfig"
@ -79,14 +77,14 @@ source "drivers/staging/rtl8187se/Kconfig"
source "drivers/staging/rtl8192su/Kconfig"
source "drivers/staging/rtl8192u/Kconfig"
source "drivers/staging/rtl8192e/Kconfig"
source "drivers/staging/mimio/Kconfig"
source "drivers/staging/frontier/Kconfig"
source "drivers/staging/android/Kconfig"
source "drivers/staging/dream/Kconfig"
source "drivers/staging/dst/Kconfig"
@ -127,6 +125,16 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
source "drivers/staging/ramzswap/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
source "drivers/staging/batman-adv/Kconfig"
source "drivers/staging/samsung-laptop/Kconfig"
source "drivers/staging/strip/Kconfig"
source "drivers/staging/arlan/Kconfig"

View File

@ -15,18 +15,17 @@ obj-$(CONFIG_POCH) += poch/
obj-$(CONFIG_OTUS) += otus/
obj-$(CONFIG_RT2860) += rt2860/
obj-$(CONFIG_RT2870) += rt2870/
obj-$(CONFIG_RT3090) += rt3090/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_ASUS_OLED) += asus_oled/
obj-$(CONFIG_PANEL) += panel/
obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/
obj-$(CONFIG_RTL8187SE) += rtl8187se/
obj-$(CONFIG_R8187SE) += rtl8187se/
obj-$(CONFIG_RTL8192SU) += rtl8192su/
obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_INPUT_MIMIO) += mimio/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_ANDROID) += dream/
obj-$(CONFIG_DREAM) += dream/
obj-$(CONFIG_DST) += dst/
obj-$(CONFIG_POHMELFS) += pohmelfs/
obj-$(CONFIG_B3DFG) += b3dfg/
@ -44,6 +43,11 @@ obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_RAR_REGISTER) += rar/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_RAMZSWAP) += ramzswap/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/
obj-$(CONFIG_STRIP) += strip/
obj-$(CONFIG_ARLAN) += arlan/
obj-$(CONFIG_WAVELAN) += wavelan/

View File

@ -212,7 +212,7 @@ struct ape_dev {
int msi_enabled;
/* whether this driver could obtain the regions */
int got_regions;
/* irq line succesfully requested by this driver, -1 otherwise */
/* irq line successfully requested by this driver, -1 otherwise */
int irq_line;
/* board revision */
u8 revision;
@ -336,7 +336,7 @@ static int __devinit map_bars(struct ape_dev *ape, struct pci_dev *dev)
printk(KERN_DEBUG "BAR[%d] mapped at 0x%p with length %lu(/%lu).\n", i,
ape->bar[i], bar_min_len[i], bar_length);
}
/* succesfully mapped all required BAR regions */
/* successfully mapped all required BAR regions */
rc = 0;
goto success;
fail:
@ -911,7 +911,7 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id)
/* perform DMA engines loop back test */
rc = dma_test(ape, dev);
(void)rc;
/* succesfully took the device */
/* successfully took the device */
rc = 0;
printk(KERN_DEBUG "probe() successful.\n");
goto end;

View File

@ -1,96 +0,0 @@
menu "Android"
config ANDROID
bool "Android Drivers"
depends on BROKEN
default N
---help---
Enable support for various drivers needed on the Android platform
if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
default n
config ANDROID_LOGGER
tristate "Android log driver"
default n
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
default n
config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
bool "Enable verbose console messages on Android RAM console"
default y
depends on ANDROID_RAM_CONSOLE
menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION
bool "Android RAM Console Enable error correction"
default n
depends on ANDROID_RAM_CONSOLE
depends on !ANDROID_RAM_CONSOLE_EARLY_INIT
select REED_SOLOMON
select REED_SOLOMON_ENC8
select REED_SOLOMON_DEC8
if ANDROID_RAM_CONSOLE_ERROR_CORRECTION
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
int "Android RAM Console Data data size"
default 128
help
Must be a power of 2.
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
int "Android RAM Console ECC size"
default 16
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
int "Android RAM Console Symbol size"
default 8
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
hex "Android RAM Console Polynomial"
default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4)
default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5)
default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6)
default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7)
default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8)
endif # ANDROID_RAM_CONSOLE_ERROR_CORRECTION
config ANDROID_RAM_CONSOLE_EARLY_INIT
bool "Start Android RAM console early"
default n
depends on ANDROID_RAM_CONSOLE
config ANDROID_RAM_CONSOLE_EARLY_ADDR
hex "Android RAM console virtual address"
default 0
depends on ANDROID_RAM_CONSOLE_EARLY_INIT
config ANDROID_RAM_CONSOLE_EARLY_SIZE
hex "Android RAM console buffer size"
default 0
depends on ANDROID_RAM_CONSOLE_EARLY_INIT
config ANDROID_TIMED_OUTPUT
bool "Timed output class driver"
default y
config ANDROID_TIMED_GPIO
tristate "Android timed gpio driver"
depends on GENERIC_GPIO && ANDROID_TIMED_OUTPUT
default n
config ANDROID_LOW_MEMORY_KILLER
bool "Android Low Memory Killer"
default N
---help---
Register processes to be killed when memory is low
endif # if ANDROID
endmenu

View File

@ -1,6 +0,0 @@
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o

View File

@ -1,10 +0,0 @@
TODO:
- checkpatch.pl cleanups
- sparse fixes
- rename files to be not so "generic"
- make sure things build as modules properly
- add proper arch dependancies as needed
- audit userspace interfaces to make sure they are sane
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
Brian Swetland <swetland@google.com>

File diff suppressed because it is too large Load Diff

View File

@ -1,330 +0,0 @@
/*
* Copyright (C) 2008 Google, Inc.
*
* Based on, but no longer compatible with, the original
* OpenBinder.org binder driver interface, which is:
*
* Copyright (c) 2005 Palmsource, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#ifndef _LINUX_BINDER_H
#define _LINUX_BINDER_H
#include <linux/ioctl.h>
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
enum {
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
};
/*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void *cookie;
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
* translate the buffer (and local binder) addresses apropriately.
*/
struct binder_write_read {
signed long write_size; /* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
/* driver protocol version -- increment with incompatible change */
signed long protocol_version;
};
/* This is the current protocol version. */
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int)
#define BINDER_THREAD_EXIT _IOW('b', 8, int)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/*
* NOTE: Two special error codes you should check for when calling
* in to the driver are:
*
* EINTR -- The operation has been interupted. This should be
* handled by retrying the ioctl() until a different error code
* is returned.
*
* ECONNREFUSED -- The driver is no longer accepting operations
* from your process. That is, the process is being destroyed.
* You should handle this by exiting from your process. Note
* that once this error code is returned, all further calls to
* the driver from any thread will return this same code.
*/
enum transaction_flags {
TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
};
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
size_t handle; /* target descriptor of command transaction */
void *ptr; /* target descriptor of return transaction */
} target;
void *cookie; /* target object cookie */
unsigned int code; /* transaction command */
/* General information about the transaction. */
unsigned int flags;
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* number of bytes of data */
size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
const void *buffer;
/* offsets from buffer to flat_binder_object structs */
const void *offsets;
} ptr;
uint8_t buf[8];
} data;
};
struct binder_ptr_cookie {
void *ptr;
void *cookie;
};
struct binder_pri_desc {
int priority;
int desc;
};
struct binder_pri_ptr_cookie {
int priority;
void *ptr;
void *cookie;
};
enum BinderDriverReturnProtocol {
BR_ERROR = _IOR('r', 0, int),
/*
* int: error code
*/
BR_OK = _IO('r', 1),
/* No parameters! */
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/*
* binder_transaction_data: the received command.
*/
BR_ACQUIRE_RESULT = _IOR('r', 4, int),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
* Else the remote object has acquired a primary reference.
*/
BR_DEAD_REPLY = _IO('r', 5),
/*
* The target of the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
*/
BR_TRANSACTION_COMPLETE = _IO('r', 6),
/*
* No parameters... always refers to the last transaction requested
* (including replies). Note that this will be sent even for
* asynchronous transactions.
*/
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/*
* not currently supported
* int: priority
* void *: ptr to binder
* void *: cookie for binder
*/
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
BR_SPAWN_LOOPER = _IO('r', 13),
/*
* No parameters. The driver has determined that a process has no
* threads waiting to service incomming transactions. When a process
* receives this command, it must spawn a new service thread and
* register it via bcENTER_LOOPER.
*/
BR_FINISHED = _IO('r', 14),
/*
* not currently supported
* stop threadpool thread
*/
BR_DEAD_BINDER = _IOR('r', 15, void *),
/*
* void *: cookie
*/
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
/*
* void *: cookie
*/
BR_FAILED_REPLY = _IO('r', 17),
/*
* The the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
*/
};
enum BinderDriverCommandProtocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
/*
* binder_transaction_data: the sent command.
*/
BC_ACQUIRE_RESULT = _IOW('c', 2, int),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
BC_FREE_BUFFER = _IOW('c', 3, int),
/*
* void *: ptr to transaction data received on a read
*/
BC_INCREFS = _IOW('c', 4, int),
BC_ACQUIRE = _IOW('c', 5, int),
BC_RELEASE = _IOW('c', 6, int),
BC_DECREFS = _IOW('c', 7, int),
/*
* int: descriptor
*/
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
/*
* not currently supported
* int: priority
* int: descriptor
*/
BC_REGISTER_LOOPER = _IO('c', 11),
/*
* No parameters.
* Register a spawned looper thread with the device.
*/
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
/*
* No parameters.
* These two commands are sent as an application-level thread
* enters and exits the binder loop, respectively. They are
* used so the binder can have an accurate count of the number
* of looping threads it has available.
*/
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
/*
* void *: cookie
*/
};
#endif /* _LINUX_BINDER_H */

View File

@ -1,607 +0,0 @@
/*
* drivers/misc/logger.c
*
* A Logging Subsystem
*
* Copyright (C) 2007-2008 Google, Inc.
*
* Robert Love <rlove@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/time.h>
#include "logger.h"
#include <asm/ioctls.h>
/*
* struct logger_log - represents a specific log, such as 'main' or 'radio'
*
* This structure lives from module insertion until module removal, so it does
* not need additional reference counting. The structure is protected by the
* mutex 'mutex'.
*/
struct logger_log {
unsigned char *buffer;/* the ring buffer itself */
struct miscdevice misc; /* misc device representing the log */
wait_queue_head_t wq; /* wait queue for readers */
struct list_head readers; /* this log's readers */
struct mutex mutex; /* mutex protecting buffer */
size_t w_off; /* current write head offset */
size_t head; /* new readers start here */
size_t size; /* size of the log */
};
/*
* struct logger_reader - a logging device open for reading
*
* This object lives from open to release, so we don't need additional
* reference counting. The structure is protected by log->mutex.
*/
struct logger_reader {
struct logger_log *log; /* associated log */
struct list_head list; /* entry in logger_log's list */
size_t r_off; /* current read head offset */
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
#define logger_offset(n) ((n) & (log->size - 1))
/*
* file_get_log - Given a file structure, return the associated log
*
* This isn't aesthetic. We have several goals:
*
* 1) Need to quickly obtain the associated log during an I/O operation
* 2) Readers need to maintain state (logger_reader)
* 3) Writers need to be very fast (open() should be a near no-op)
*
* In the reader case, we can trivially go file->logger_reader->logger_log.
* For a writer, we don't want to maintain a logger_reader, so we just go
* file->logger_log. Thus what file->private_data points at depends on whether
* or not the file was opened for reading. This function hides that dirtiness.
*/
static inline struct logger_log *file_get_log(struct file *file)
{
if (file->f_mode & FMODE_READ) {
struct logger_reader *reader = file->private_data;
return reader->log;
} else
return file->private_data;
}
/*
* get_entry_len - Grabs the length of the payload of the next entry starting
* from 'off'.
*
* Caller needs to hold log->mutex.
*/
static __u32 get_entry_len(struct logger_log *log, size_t off)
{
__u16 val;
switch (log->size - off) {
case 1:
memcpy(&val, log->buffer + off, 1);
memcpy(((char *) &val) + 1, log->buffer, 1);
break;
default:
memcpy(&val, log->buffer + off, 2);
}
return sizeof(struct logger_entry) + val;
}
/*
* do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
* user-space buffer 'buf'. Returns 'count' on success.
*
* Caller must hold log->mutex.
*/
static ssize_t do_read_log_to_user(struct logger_log *log,
struct logger_reader *reader,
char __user *buf,
size_t count)
{
size_t len;
/*
* We read from the log in two disjoint operations. First, we read from
* the current read head offset up to 'count' bytes or to the end of
* the log, whichever comes first.
*/
len = min(count, log->size - reader->r_off);
if (copy_to_user(buf, log->buffer + reader->r_off, len))
return -EFAULT;
/*
* Second, we read any remaining bytes, starting back at the head of
* the log.
*/
if (count != len)
if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT;
reader->r_off = logger_offset(reader->r_off + count);
return count;
}
/*
* logger_read - our log's read() method
*
* Behavior:
*
* - O_NONBLOCK works
* - If there are no log entries to read, blocks until log is written to
* - Atomically reads exactly one log entry
*
* Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
* buffer is insufficient to hold next entry.
*/
static ssize_t logger_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
struct logger_reader *reader = file->private_data;
struct logger_log *log = reader->log;
ssize_t ret;
DEFINE_WAIT(wait);
start:
while (1) {
prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
mutex_lock(&log->mutex);
ret = (log->w_off == reader->r_off);
mutex_unlock(&log->mutex);
if (!ret)
break;
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
}
if (signal_pending(current)) {
ret = -EINTR;
break;
}
schedule();
}
finish_wait(&log->wq, &wait);
if (ret)
return ret;
mutex_lock(&log->mutex);
/* is there still something to read or did we race? */
if (unlikely(log->w_off == reader->r_off)) {
mutex_unlock(&log->mutex);
goto start;
}
/* get the size of the next entry */
ret = get_entry_len(log, reader->r_off);
if (count < ret) {
ret = -EINVAL;
goto out;
}
/* get exactly one entry from the log */
ret = do_read_log_to_user(log, reader, buf, ret);
out:
mutex_unlock(&log->mutex);
return ret;
}
/*
* get_next_entry - return the offset of the first valid entry at least 'len'
* bytes after 'off'.
*
* Caller must hold log->mutex.
*/
static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
{
size_t count = 0;
do {
size_t nr = get_entry_len(log, off);
off = logger_offset(off + nr);
count += nr;
} while (count < len);
return off;
}
/*
* clock_interval - is a < c < b in mod-space? Put another way, does the line
* from a to b cross c?
*/
static inline int clock_interval(size_t a, size_t b, size_t c)
{
if (b < a) {
if (a < c || b >= c)
return 1;
} else {
if (a < c && b >= c)
return 1;
}
return 0;
}
/*
* fix_up_readers - walk the list of all readers and "fix up" any who were
* lapped by the writer; also do the same for the default "start head".
* We do this by "pulling forward" the readers and start head to the first
* entry after the new write head.
*
* The caller needs to hold log->mutex.
*/
static void fix_up_readers(struct logger_log *log, size_t len)
{
size_t old = log->w_off;
size_t new = logger_offset(old + len);
struct logger_reader *reader;
if (clock_interval(old, new, log->head))
log->head = get_next_entry(log, log->head, len);
list_for_each_entry(reader, &log->readers, list)
if (clock_interval(old, new, reader->r_off))
reader->r_off = get_next_entry(log, reader->r_off, len);
}
/*
* do_write_log - writes 'len' bytes from 'buf' to 'log'
*
* The caller needs to hold log->mutex.
*/
static void do_write_log(struct logger_log *log, const void *buf, size_t count)
{
size_t len;
len = min(count, log->size - log->w_off);
memcpy(log->buffer + log->w_off, buf, len);
if (count != len)
memcpy(log->buffer, buf + len, count - len);
log->w_off = logger_offset(log->w_off + count);
}
/*
* do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to
* the log 'log'
*
* The caller needs to hold log->mutex.
*
* Returns 'count' on success, negative error code on failure.
*/
static ssize_t do_write_log_from_user(struct logger_log *log,
const void __user *buf, size_t count)
{
size_t len;
len = min(count, log->size - log->w_off);
if (len && copy_from_user(log->buffer + log->w_off, buf, len))
return -EFAULT;
if (count != len)
if (copy_from_user(log->buffer, buf + len, count - len))
return -EFAULT;
log->w_off = logger_offset(log->w_off + count);
return count;
}
/*
* logger_aio_write - our write method, implementing support for write(),
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
* them above all else.
*/
ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t ppos)
{
struct logger_log *log = file_get_log(iocb->ki_filp);
size_t orig = log->w_off;
struct logger_entry header;
struct timespec now;
ssize_t ret = 0;
now = current_kernel_time();
header.pid = current->tgid;
header.tid = current->pid;
header.sec = now.tv_sec;
header.nsec = now.tv_nsec;
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
/* null writes succeed, return zero */
if (unlikely(!header.len))
return 0;
mutex_lock(&log->mutex);
/*
* Fix up any readers, pulling them forward to the first readable
* entry after (what will be) the new write offset. We do this now
* because if we partially fail, we can end up with clobbered log
* entries that encroach on readable buffer.
*/
fix_up_readers(log, sizeof(struct logger_entry) + header.len);
do_write_log(log, &header, sizeof(struct logger_entry));
while (nr_segs-- > 0) {
size_t len;
ssize_t nr;
/* figure out how much of this vector we can keep */
len = min_t(size_t, iov->iov_len, header.len - ret);
/* write out this segment's payload */
nr = do_write_log_from_user(log, iov->iov_base, len);
if (unlikely(nr < 0)) {
log->w_off = orig;
mutex_unlock(&log->mutex);
return nr;
}
iov++;
ret += nr;
}
mutex_unlock(&log->mutex);
/* wake up any blocked readers */
wake_up_interruptible(&log->wq);
return ret;
}
static struct logger_log *get_log_from_minor(int);
/*
* logger_open - the log's open() file operation
*
* Note how near a no-op this is in the write-only case. Keep it that way!
*/
static int logger_open(struct inode *inode, struct file *file)
{
struct logger_log *log;
int ret;
ret = nonseekable_open(inode, file);
if (ret)
return ret;
log = get_log_from_minor(MINOR(inode->i_rdev));
if (!log)
return -ENODEV;
if (file->f_mode & FMODE_READ) {
struct logger_reader *reader;
reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
if (!reader)
return -ENOMEM;
reader->log = log;
INIT_LIST_HEAD(&reader->list);
mutex_lock(&log->mutex);
reader->r_off = log->head;
list_add_tail(&reader->list, &log->readers);
mutex_unlock(&log->mutex);
file->private_data = reader;
} else
file->private_data = log;
return 0;
}
/*
* logger_release - the log's release file operation
*
* Note this is a total no-op in the write-only case. Keep it that way!
*/
static int logger_release(struct inode *ignored, struct file *file)
{
if (file->f_mode & FMODE_READ) {
struct logger_reader *reader = file->private_data;
list_del(&reader->list);
kfree(reader);
}
return 0;
}
/*
* logger_poll - the log's poll file operation, for poll/select/epoll
*
* Note we always return POLLOUT, because you can always write() to the log.
* Note also that, strictly speaking, a return value of POLLIN does not
* guarantee that the log is readable without blocking, as there is a small
* chance that the writer can lap the reader in the interim between poll()
* returning and the read() request.
*/
static unsigned int logger_poll(struct file *file, poll_table *wait)
{
struct logger_reader *reader;
struct logger_log *log;
unsigned int ret = POLLOUT | POLLWRNORM;
if (!(file->f_mode & FMODE_READ))
return ret;
reader = file->private_data;
log = reader->log;
poll_wait(file, &log->wq, wait);
mutex_lock(&log->mutex);
if (log->w_off != reader->r_off)
ret |= POLLIN | POLLRDNORM;
mutex_unlock(&log->mutex);
return ret;
}
static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct logger_log *log = file_get_log(file);
struct logger_reader *reader;
long ret = -ENOTTY;
mutex_lock(&log->mutex);
switch (cmd) {
case LOGGER_GET_LOG_BUF_SIZE:
ret = log->size;
break;
case LOGGER_GET_LOG_LEN:
if (!(file->f_mode & FMODE_READ)) {
ret = -EBADF;
break;
}
reader = file->private_data;
if (log->w_off >= reader->r_off)
ret = log->w_off - reader->r_off;
else
ret = (log->size - reader->r_off) + log->w_off;
break;
case LOGGER_GET_NEXT_ENTRY_LEN:
if (!(file->f_mode & FMODE_READ)) {
ret = -EBADF;
break;
}
reader = file->private_data;
if (log->w_off != reader->r_off)
ret = get_entry_len(log, reader->r_off);
else
ret = 0;
break;
case LOGGER_FLUSH_LOG:
if (!(file->f_mode & FMODE_WRITE)) {
ret = -EBADF;
break;
}
list_for_each_entry(reader, &log->readers, list)
reader->r_off = log->w_off;
log->head = log->w_off;
ret = 0;
break;
}
mutex_unlock(&log->mutex);
return ret;
}
static const struct file_operations logger_fops = {
.owner = THIS_MODULE,
.read = logger_read,
.aio_write = logger_aio_write,
.poll = logger_poll,
.unlocked_ioctl = logger_ioctl,
.compat_ioctl = logger_ioctl,
.open = logger_open,
.release = logger_release,
};
/*
* Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
* must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
* LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
*/
#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
static unsigned char _buf_ ## VAR[SIZE]; \
static struct logger_log VAR = { \
.buffer = _buf_ ## VAR, \
.misc = { \
.minor = MISC_DYNAMIC_MINOR, \
.name = NAME, \
.fops = &logger_fops, \
.parent = NULL, \
}, \
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
.readers = LIST_HEAD_INIT(VAR .readers), \
.mutex = __MUTEX_INITIALIZER(VAR .mutex), \
.w_off = 0, \
.head = 0, \
.size = SIZE, \
};
DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
static struct logger_log *get_log_from_minor(int minor)
{
if (log_main.misc.minor == minor)
return &log_main;
if (log_events.misc.minor == minor)
return &log_events;
if (log_radio.misc.minor == minor)
return &log_radio;
return NULL;
}
static int __init init_log(struct logger_log *log)
{
int ret;
ret = misc_register(&log->misc);
if (unlikely(ret)) {
printk(KERN_ERR "logger: failed to register misc "
"device for log '%s'!\n", log->misc.name);
return ret;
}
printk(KERN_INFO "logger: created %luK log '%s'\n",
(unsigned long) log->size >> 10, log->misc.name);
return 0;
}
static int __init logger_init(void)
{
int ret;
ret = init_log(&log_main);
if (unlikely(ret))
goto out;
ret = init_log(&log_events);
if (unlikely(ret))
goto out;
ret = init_log(&log_radio);
if (unlikely(ret))
goto out;
out:
return ret;
}
device_initcall(logger_init);

View File

@ -1,48 +0,0 @@
/* include/linux/logger.h
*
* Copyright (C) 2007-2008 Google, Inc.
* Author: Robert Love <rlove@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#ifndef _LINUX_LOGGER_H
#define _LINUX_LOGGER_H
#include <linux/types.h>
#include <linux/ioctl.h>
struct logger_entry {
__u16 len; /* length of the payload */
__u16 __pad; /* no matter what, we get 2 bytes of padding */
__s32 pid; /* generating process's pid */
__s32 tid; /* generating process's tid */
__s32 sec; /* seconds since Epoch */
__s32 nsec; /* nanoseconds */
char msg[0]; /* the entry's payload */
};
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
#define LOGGER_LOG_MAIN "log_main" /* everything else */
#define LOGGER_ENTRY_MAX_LEN (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD \
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
#define __LOGGERIO 0xAE
#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
#endif /* _LINUX_LOGGER_H */

View File

@ -1,173 +0,0 @@
/* drivers/misc/lowmemorykiller.c
*
* The lowmemorykiller driver lets user-space specify a set of memory thresholds
* where processes with a range of oom_adj values will get killed. Specify the
* minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the
* number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both
* files take a comma separated list of numbers in ascending order.
*
* For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
* "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill processes
* with a oom_adj value of 8 or higher when the free memory drops below 4096 pages
* and kill processes with a oom_adj value of 0 or higher when the free memory
* drops below 1024 pages.
*
* The driver considers memory used for caches to be free, but if a large
* percentage of the cached memory is locked this can be very inaccurate
* and processes may not get killed until the normal oom killer is triggered.
*
* Copyright (C) 2007-2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/oom.h>
#include <linux/sched.h>
static uint32_t lowmem_debug_level = 2;
static int lowmem_adj[6] = {
0,
1,
6,
12,
};
static int lowmem_adj_size = 4;
static size_t lowmem_minfree[6] = {
3 * 512, /* 6MB */
2 * 1024, /* 8MB */
4 * 1024, /* 16MB */
16 * 1024, /* 64MB */
};
static int lowmem_minfree_size = 4;
#define lowmem_print(level, x...) \
do { \
if (lowmem_debug_level >= (level)) \
printk(x); \
} while (0)
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{
struct task_struct *p;
struct task_struct *selected = NULL;
int rem = 0;
int tasksize;
int i;
int min_adj = OOM_ADJUST_MAX + 1;
int selected_tasksize = 0;
int selected_oom_adj;
int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES);
int other_file = global_page_state(NR_FILE_PAGES);
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
if (lowmem_minfree_size < array_size)
array_size = lowmem_minfree_size;
for (i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}
if (nr_to_scan > 0)
lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n",
nr_to_scan, gfp_mask, other_free, other_file,
min_adj);
rem = global_page_state(NR_ACTIVE_ANON) +
global_page_state(NR_ACTIVE_FILE) +
global_page_state(NR_INACTIVE_ANON) +
global_page_state(NR_INACTIVE_FILE);
if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
lowmem_print(5, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
return rem;
}
selected_oom_adj = min_adj;
read_lock(&tasklist_lock);
for_each_process(p) {
struct mm_struct *mm;
int oom_adj;
task_lock(p);
mm = p->mm;
if (!mm) {
task_unlock(p);
continue;
}
oom_adj = mm->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
}
if (selected) {
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}
lowmem_print(4, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
read_unlock(&tasklist_lock);
return rem;
}
static struct shrinker lowmem_shrinker = {
.shrink = lowmem_shrink,
.seeks = DEFAULT_SEEKS * 16
};
static int __init lowmem_init(void)
{
register_shrinker(&lowmem_shrinker);
return 0;
}
static void __exit lowmem_exit(void)
{
unregister_shrinker(&lowmem_shrinker);
}
module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size,
S_IRUGO | S_IWUSR);
module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
S_IRUGO | S_IWUSR);
module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
module_init(lowmem_init);
module_exit(lowmem_exit);
MODULE_LICENSE("GPL");

View File

@ -1,410 +0,0 @@
/* drivers/android/ram_console.c
*
* Copyright (C) 2007-2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
#include <linux/rslib.h>
#endif
struct ram_console_buffer {
uint32_t sig;
uint32_t start;
uint32_t size;
uint8_t data[0];
};
#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
static char __initdata
ram_console_old_log_init_buffer[CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE];
#endif
static char *ram_console_old_log;
static size_t ram_console_old_log_size;
static struct ram_console_buffer *ram_console_buffer;
static size_t ram_console_buffer_size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
static char *ram_console_par_buffer;
static struct rs_control *ram_console_rs_decoder;
static int ram_console_corrected_bytes;
static int ram_console_bad_blocks;
#define ECC_BLOCK_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
#define ECC_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
#define ECC_SYMSIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
#define ECC_POLY CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
#endif
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
static void ram_console_encode_rs8(uint8_t *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[ECC_SIZE];
/* Initialize the parity buffer */
memset(par, 0, sizeof(par));
encode_rs8(ram_console_rs_decoder, data, len, par, 0);
for (i = 0; i < ECC_SIZE; i++)
ecc[i] = par[i];
}
static int ram_console_decode_rs8(void *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[ECC_SIZE];
for (i = 0; i < ECC_SIZE; i++)
par[i] = ecc[i];
return decode_rs8(ram_console_rs_decoder, data, par, len,
NULL, 0, NULL, 0, NULL);
}
#endif
static void ram_console_update(const char *s, unsigned int count)
{
struct ram_console_buffer *buffer = ram_console_buffer;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *buffer_end = buffer->data + ram_console_buffer_size;
uint8_t *block;
uint8_t *par;
int size = ECC_BLOCK_SIZE;
#endif
memcpy(buffer->data + buffer->start, s, count);
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
block = buffer->data + (buffer->start & ~(ECC_BLOCK_SIZE - 1));
par = ram_console_par_buffer +
(buffer->start / ECC_BLOCK_SIZE) * ECC_SIZE;
do {
if (block + ECC_BLOCK_SIZE > buffer_end)
size = buffer_end - block;
ram_console_encode_rs8(block, size, par);
block += ECC_BLOCK_SIZE;
par += ECC_SIZE;
} while (block < buffer->data + buffer->start + count);
#endif
}
static void ram_console_update_header(void)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
struct ram_console_buffer *buffer = ram_console_buffer;
uint8_t *par;
par = ram_console_par_buffer +
DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
ram_console_encode_rs8((uint8_t *)buffer, sizeof(*buffer), par);
#endif
}
static void
ram_console_write(struct console *console, const char *s, unsigned int count)
{
int rem;
struct ram_console_buffer *buffer = ram_console_buffer;
if (count > ram_console_buffer_size) {
s += count - ram_console_buffer_size;
count = ram_console_buffer_size;
}
rem = ram_console_buffer_size - buffer->start;
if (rem < count) {
ram_console_update(s, rem);
s += rem;
count -= rem;
buffer->start = 0;
buffer->size = ram_console_buffer_size;
}
ram_console_update(s, count);
buffer->start += count;
if (buffer->size < ram_console_buffer_size)
buffer->size += count;
ram_console_update_header();
}
static struct console ram_console = {
.name = "ram",
.write = ram_console_write,
.flags = CON_PRINTBUFFER | CON_ENABLED,
.index = -1,
};
static void __init
ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
{
size_t old_log_size = buffer->size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *block;
uint8_t *par;
char strbuf[80];
int strbuf_len;
block = buffer->data;
par = ram_console_par_buffer;
while (block < buffer->data + buffer->size) {
int numerr;
int size = ECC_BLOCK_SIZE;
if (block + size > buffer->data + ram_console_buffer_size)
size = buffer->data + ram_console_buffer_size - block;
numerr = ram_console_decode_rs8(block, size, par);
if (numerr > 0) {
#if 0
printk(KERN_INFO "ram_console: error in block %p, %d\n",
block, numerr);
#endif
ram_console_corrected_bytes += numerr;
} else if (numerr < 0) {
#if 0
printk(KERN_INFO "ram_console: uncorrectable error in "
"block %p\n", block);
#endif
ram_console_bad_blocks++;
}
block += ECC_BLOCK_SIZE;
par += ECC_SIZE;
}
if (ram_console_corrected_bytes || ram_console_bad_blocks)
strbuf_len = snprintf(strbuf, sizeof(strbuf),
"\n%d Corrected bytes, %d unrecoverable blocks\n",
ram_console_corrected_bytes, ram_console_bad_blocks);
else
strbuf_len = snprintf(strbuf, sizeof(strbuf),
"\nNo errors detected\n");
if (strbuf_len >= sizeof(strbuf))
strbuf_len = sizeof(strbuf) - 1;
old_log_size += strbuf_len;
#endif
if (dest == NULL) {
dest = kmalloc(old_log_size, GFP_KERNEL);
if (dest == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer\n");
return;
}
}
ram_console_old_log = dest;
ram_console_old_log_size = old_log_size;
memcpy(ram_console_old_log,
&buffer->data[buffer->start], buffer->size - buffer->start);
memcpy(ram_console_old_log + buffer->size - buffer->start,
&buffer->data[0], buffer->start);
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
memcpy(ram_console_old_log + old_log_size - strbuf_len,
strbuf, strbuf_len);
#endif
}
static int __init ram_console_init(struct ram_console_buffer *buffer,
size_t buffer_size, char *old_buf)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
int numerr;
uint8_t *par;
#endif
ram_console_buffer = buffer;
ram_console_buffer_size =
buffer_size - sizeof(struct ram_console_buffer);
if (ram_console_buffer_size > buffer_size) {
pr_err("ram_console: buffer %p, invalid size %zu, "
"datasize %zu\n", buffer, buffer_size,
ram_console_buffer_size);
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
ram_console_buffer_size -= (DIV_ROUND_UP(ram_console_buffer_size,
ECC_BLOCK_SIZE) + 1) * ECC_SIZE;
if (ram_console_buffer_size > buffer_size) {
pr_err("ram_console: buffer %p, invalid size %zu, "
"non-ecc datasize %zu\n",
buffer, buffer_size, ram_console_buffer_size);
return 0;
}
ram_console_par_buffer = buffer->data + ram_console_buffer_size;
/* first consecutive root is 0
* primitive element to generate roots = 1
*/
ram_console_rs_decoder = init_rs(ECC_SYMSIZE, ECC_POLY, 0, 1, ECC_SIZE);
if (ram_console_rs_decoder == NULL) {
printk(KERN_INFO "ram_console: init_rs failed\n");
return 0;
}
ram_console_corrected_bytes = 0;
ram_console_bad_blocks = 0;
par = ram_console_par_buffer +
DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
numerr = ram_console_decode_rs8(buffer, sizeof(*buffer), par);
if (numerr > 0) {
printk(KERN_INFO "ram_console: error in header, %d\n", numerr);
ram_console_corrected_bytes += numerr;
} else if (numerr < 0) {
printk(KERN_INFO
"ram_console: uncorrectable error in header\n");
ram_console_bad_blocks++;
}
#endif
if (buffer->sig == RAM_CONSOLE_SIG) {
if (buffer->size > ram_console_buffer_size
|| buffer->start > buffer->size)
printk(KERN_INFO "ram_console: found existing invalid "
"buffer, size %d, start %d\n",
buffer->size, buffer->start);
else {
printk(KERN_INFO "ram_console: found existing buffer, "
"size %d, start %d\n",
buffer->size, buffer->start);
ram_console_save_old(buffer, old_buf);
}
} else {
printk(KERN_INFO "ram_console: no valid data in buffer "
"(sig = 0x%08x)\n", buffer->sig);
}
buffer->sig = RAM_CONSOLE_SIG;
buffer->start = 0;
buffer->size = 0;
register_console(&ram_console);
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
console_verbose();
#endif
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
static int __init ram_console_early_init(void)
{
return ram_console_init((struct ram_console_buffer *)
CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR,
CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,
ram_console_old_log_init_buffer);
}
#else
static int ram_console_driver_probe(struct platform_device *pdev)
{
struct resource *res = pdev->resource;
size_t start;
size_t buffer_size;
void *buffer;
if (res == NULL || pdev->num_resources != 1 ||
!(res->flags & IORESOURCE_MEM)) {
printk(KERN_ERR "ram_console: invalid resource, %p %d flags "
"%lx\n", res, pdev->num_resources, res ? res->flags : 0);
return -ENXIO;
}
buffer_size = res->end - res->start + 1;
start = res->start;
printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
start, buffer_size);
buffer = ioremap(res->start, buffer_size);
if (buffer == NULL) {
printk(KERN_ERR "ram_console: failed to map memory\n");
return -ENOMEM;
}
return ram_console_init(buffer, buffer_size, NULL/* allocate */);
}
static struct platform_driver ram_console_driver = {
.probe = ram_console_driver_probe,
.driver = {
.name = "ram_console",
},
};
static int __init ram_console_module_init(void)
{
int err;
err = platform_driver_register(&ram_console_driver);
return err;
}
#endif
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
size_t len, loff_t *offset)
{
loff_t pos = *offset;
ssize_t count;
if (pos >= ram_console_old_log_size)
return 0;
count = min(len, (size_t)(ram_console_old_log_size - pos));
if (copy_to_user(buf, ram_console_old_log + pos, count))
return -EFAULT;
*offset += count;
return count;
}
static const struct file_operations ram_console_file_ops = {
.owner = THIS_MODULE,
.read = ram_console_read_old,
};
static int __init ram_console_late_init(void)
{
struct proc_dir_entry *entry;
if (ram_console_old_log == NULL)
return 0;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL);
if (ram_console_old_log == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer for old log\n");
ram_console_old_log_size = 0;
return 0;
}
memcpy(ram_console_old_log,
ram_console_old_log_init_buffer, ram_console_old_log_size);
#endif
entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
if (!entry) {
printk(KERN_ERR "ram_console: failed to create proc entry\n");
kfree(ram_console_old_log);
ram_console_old_log = NULL;
return 0;
}
entry->proc_fops = &ram_console_file_ops;
entry->size = ram_console_old_log_size;
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
console_initcall(ram_console_early_init);
#else
module_init(ram_console_module_init);
#endif
late_initcall(ram_console_late_init);

View File

@ -1,166 +0,0 @@
/* drivers/misc/timed_gpio.c
*
* Copyright (C) 2008 Google, Inc.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/hrtimer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include "timed_output.h"
#include "timed_gpio.h"
struct timed_gpio_data {
struct timed_output_dev dev;
struct hrtimer timer;
spinlock_t lock;
unsigned gpio;
int max_timeout;
u8 active_low;
};
static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
{
struct timed_gpio_data *data =
container_of(timer, struct timed_gpio_data, timer);
gpio_direction_output(data->gpio, data->active_low ? 1 : 0);
return HRTIMER_NORESTART;
}
static int gpio_get_time(struct timed_output_dev *dev)
{
struct timed_gpio_data *data =
container_of(dev, struct timed_gpio_data, dev);
if (hrtimer_active(&data->timer)) {
ktime_t r = hrtimer_get_remaining(&data->timer);
struct timeval t = ktime_to_timeval(r);
return t.tv_sec * 1000 + t.tv_usec / 1000;
} else
return 0;
}
static void gpio_enable(struct timed_output_dev *dev, int value)
{
struct timed_gpio_data *data =
container_of(dev, struct timed_gpio_data, dev);
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
/* cancel previous timer and set GPIO according to value */
hrtimer_cancel(&data->timer);
gpio_direction_output(data->gpio, data->active_low ? !value : !!value);
if (value > 0) {
if (value > data->max_timeout)
value = data->max_timeout;
hrtimer_start(&data->timer,
ktime_set(value / 1000, (value % 1000) * 1000000),
HRTIMER_MODE_REL);
}
spin_unlock_irqrestore(&data->lock, flags);
}
static int timed_gpio_probe(struct platform_device *pdev)
{
struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
struct timed_gpio *cur_gpio;
struct timed_gpio_data *gpio_data, *gpio_dat;
int i, j, ret = 0;
if (!pdata)
return -EBUSY;
gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios,
GFP_KERNEL);
if (!gpio_data)
return -ENOMEM;
for (i = 0; i < pdata->num_gpios; i++) {
cur_gpio = &pdata->gpios[i];
gpio_dat = &gpio_data[i];
hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
gpio_dat->timer.function = gpio_timer_func;
spin_lock_init(&gpio_dat->lock);
gpio_dat->dev.name = cur_gpio->name;
gpio_dat->dev.get_time = gpio_get_time;
gpio_dat->dev.enable = gpio_enable;
ret = timed_output_dev_register(&gpio_dat->dev);
if (ret < 0) {
for (j = 0; j < i; j++)
timed_output_dev_unregister(&gpio_data[i].dev);
kfree(gpio_data);
return ret;
}
gpio_dat->gpio = cur_gpio->gpio;
gpio_dat->max_timeout = cur_gpio->max_timeout;
gpio_dat->active_low = cur_gpio->active_low;
gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low);
}
platform_set_drvdata(pdev, gpio_data);
return 0;
}
static int timed_gpio_remove(struct platform_device *pdev)
{
struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev);
int i;
for (i = 0; i < pdata->num_gpios; i++)
timed_output_dev_unregister(&gpio_data[i].dev);
kfree(gpio_data);
return 0;
}
static struct platform_driver timed_gpio_driver = {
.probe = timed_gpio_probe,
.remove = timed_gpio_remove,
.driver = {
.name = TIMED_GPIO_NAME,
.owner = THIS_MODULE,
},
};
static int __init timed_gpio_init(void)
{
return platform_driver_register(&timed_gpio_driver);
}
static void __exit timed_gpio_exit(void)
{
platform_driver_unregister(&timed_gpio_driver);
}
module_init(timed_gpio_init);
module_exit(timed_gpio_exit);
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_DESCRIPTION("timed gpio driver");
MODULE_LICENSE("GPL");

View File

@ -1,33 +0,0 @@
/* include/linux/timed_gpio.h
*
* Copyright (C) 2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#ifndef _LINUX_TIMED_GPIO_H
#define _LINUX_TIMED_GPIO_H
#define TIMED_GPIO_NAME "timed-gpio"
struct timed_gpio {
const char *name;
unsigned gpio;
int max_timeout;
u8 active_low;
};
struct timed_gpio_platform_data {
int num_gpios;
struct timed_gpio *gpios;
};
#endif

View File

@ -1,121 +0,0 @@
/* drivers/misc/timed_output.c
*
* Copyright (C) 2009 Google, Inc.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include "timed_output.h"
static struct class *timed_output_class;
static atomic_t device_count;
static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int remaining = tdev->get_time(tdev);
return sprintf(buf, "%d\n", remaining);
}
static ssize_t enable_store(
struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int value;
sscanf(buf, "%d", &value);
tdev->enable(tdev, value);
return size;
}
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
static int create_timed_output_class(void)
{
if (!timed_output_class) {
timed_output_class = class_create(THIS_MODULE, "timed_output");
if (IS_ERR(timed_output_class))
return PTR_ERR(timed_output_class);
atomic_set(&device_count, 0);
}
return 0;
}
int timed_output_dev_register(struct timed_output_dev *tdev)
{
int ret;
if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time)
return -EINVAL;
ret = create_timed_output_class();
if (ret < 0)
return ret;
tdev->index = atomic_inc_return(&device_count);
tdev->dev = device_create(timed_output_class, NULL,
MKDEV(0, tdev->index), NULL, tdev->name);
if (IS_ERR(tdev->dev))
return PTR_ERR(tdev->dev);
ret = device_create_file(tdev->dev, &dev_attr_enable);
if (ret < 0)
goto err_create_file;
dev_set_drvdata(tdev->dev, tdev);
tdev->state = 0;
return 0;
err_create_file:
device_destroy(timed_output_class, MKDEV(0, tdev->index));
printk(KERN_ERR "timed_output: Failed to register driver %s\n",
tdev->name);
return ret;
}
EXPORT_SYMBOL_GPL(timed_output_dev_register);
void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
device_remove_file(tdev->dev, &dev_attr_enable);
device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL);
}
EXPORT_SYMBOL_GPL(timed_output_dev_unregister);
static int __init timed_output_init(void)
{
return create_timed_output_class();
}
static void __exit timed_output_exit(void)
{
class_destroy(timed_output_class);
}
module_init(timed_output_init);
module_exit(timed_output_exit);
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_DESCRIPTION("timed output class driver");
MODULE_LICENSE("GPL");

View File

@ -1,37 +0,0 @@
/* include/linux/timed_output.h
*
* Copyright (C) 2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program 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.
*
*/
#ifndef _LINUX_TIMED_OUTPUT_H
#define _LINUX_TIMED_OUTPUT_H
struct timed_output_dev {
const char *name;
/* enable the output and set the timer */
void (*enable)(struct timed_output_dev *sdev, int timeout);
/* returns the current number of milliseconds remaining on the timer */
int (*get_time)(struct timed_output_dev *sdev);
/* private data */
struct device *dev;
int index;
int state;
};
extern int timed_output_dev_register(struct timed_output_dev *dev);
extern void timed_output_dev_unregister(struct timed_output_dev *dev);
#endif

View File

@ -468,7 +468,6 @@ static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
static int enable_transmission(struct b3dfg_dev *fgdev)
{
u16 command;
unsigned long flags;
struct device *dev = &fgdev->pdev->dev;
@ -480,17 +479,6 @@ static int enable_transmission(struct b3dfg_dev *fgdev)
return -EINVAL;
}
/*
* Check we're a bus master.
* TODO: I think we can remove this having added the pci_set_master call
*/
pci_read_config_word(fgdev->pdev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_MASTER)) {
dev_err(dev, "not a bus master, force-enabling\n");
pci_write_config_word(fgdev->pdev, PCI_COMMAND,
command | PCI_COMMAND_MASTER);
}
spin_lock_irqsave(&fgdev->buffer_lock, flags);
/* Handle racing enable_transmission calls. */

View File

@ -0,0 +1,37 @@
batman-adv 0.2:
* support latest kernels (2.6.20 - 2.6.31)
* temporary routing loops / TTL code bug / ghost entries in originator table fixed
* internal packet queue for packet aggregation & transmission retry (ARQ)
for payload broadcasts added
* interface detection converted to event based handling to avoid timers
* major linux coding style adjustments applied
* all kernel version compatibility functions has been moved to compat.h
* use random ethernet address generator from the kernel
* /sys/module/batman_adv/version to export kernel module version
* vis: secondary interface export for dot draw format + JSON output format added
* many bugs (alignment issues, race conditions, deadlocks, etc) squashed
-- Sat, 07 Nov 2009 15:44:31 +0100
batman-adv 0.1:
* support latest kernels (2.6.20 - 2.6.28)
* LOTS of cleanup: locking, stack usage, memory leaks
* Change Ethertype from 0x0842 to 0x4305
unregistered at IEEE, if you want to sponsor an official Ethertype ($2500)
please contact us
-- Sun, 28 Dec 2008 00:44:31 +0100
batman-adv 0.1-beta:
* layer 2 meshing based on BATMAN TQ algorithm in kernelland
* operates on any ethernet like interface
* supports IPv4, IPv6, DHCP, etc
* is controlled via /proc/net/batman-adv/
* bridging via brctl is supported
* interface watchdog (interfaces can be (de)activated dynamically)
* offers integrated vis server which meshes/syncs with other vis servers in range
-- Mon, 05 May 2008 14:10:04 +0200

View File

@ -0,0 +1,25 @@
#
# B.A.T.M.A.N meshing protocol
#
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
default n
---help---
B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
a routing protocol for multi-hop ad-hoc mesh networks. The
networks may be wired or wireless. See
http://www.open-mesh.org/ for more information and user space
tools.
config BATMAN_DEBUG
bool "B.A.T.M.A.N. debugging"
depends on BATMAN != n
help
This is an option for use by developers; most people should
say N here. This enables compilation of support for
outputting debugging information to the kernel log. The
output is controlled via the module parameter debug.

View File

@ -0,0 +1,22 @@
#
# Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
#
# Marek Lindner, Simon Wunderlich
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA
#
obj-m += batman-adv.o
batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o log.o

View File

@ -0,0 +1,125 @@
[state: 07-11-2009]
BATMAN-ADV
----------
Batman-advanced is a new approach to wireless networking which does no longer
operate on the IP basis. Unlike B.A.T.M.A.N, which exchanges information
using UDP packets and sets routing tables, batman-advanced operates on ISO/OSI
Layer 2 only and uses and routes (or better: bridges) Ethernet Frames. It
emulates a virtual network switch of all nodes participating. Therefore all
nodes appear to be link local, thus all higher operating protocols won't be
affected by any changes within the network. You can run almost any protocol
above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX.
This is batman-advanced implemented as Linux kernel driver. It does not depend
on any network (other) driver, and can be used on wifi as well as ethernet,
vpn, etc ... (anything with ethernet-style layer 2).
It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older
versions is not planned, but it's probably easy to backport it. If you work on a
backport, feel free to contact us. :-)
COMPILE
-------
To compile against your currently installed kernel, just type:
# make
if you want to compile against some other kernel, use:
# make KERNELPATH=/path/to/kernel
USAGE
-----
insmod the batman-adv.ko in your kernel:
# insmod batman-adv.ko
the module is now waiting for activation. You must add some interfaces
on which batman can operate. Each interface must be added separately:
# echo wlan0 > /proc/net/batman-adv/interfaces
( # echo wlan1 > /proc/net/batman-adv/interfaces )
( # echo eth0 > /proc/net/batman-adv/interfaces )
( ... )
Now batman starts broadcasting on this interface.
You can now view the table of originators (mesh participants) with:
# cat /proc/net/batman-adv/originators
The module will create a new interface "bat0", which can be used as a
regular interface:
# ifconfig bat0 inet 192.168.0.1 up
# ping 192.168.0.2
...
If you want topology visualization, your meshnode must be configured
as VIS-server:
# echo "server" > /proc/net/batman-adv/vis
Each node is either configured as "server" or as "client" (default:
"client"). Clients send their topology data to the server next to them,
and server synchronize with other servers. If there is no server
configured (default) within the mesh, no topology information will be
transmitted. With these "synchronizing servers", there can be 1 or
more vis servers sharing the same (or at least very similar) data.
When configured as server, you can get a topology snapshot of your mesh:
# cat /proc/net/batman-adv/vis
This output format is a graphviz formatted text file which can be
processed with graphviz-tools like dot.
The labels are similar/compatible to the ETX metric, 1.0 means perfect
connection (100%), 2.0 means 50%, 3.0 means 33% and so on.
Alternatively, a JSON output format is available. The format can be set
using by writing either "dot_draw" or "json" into the vis_format file.
"dot_draw" is selected by default.
echo "json" > /proc/net/batman-adv/vis_format
In very mobile scenarios, you might want to adjust the originator
interval to a lower value. This will make the mesh more responsive to
topology changes, but will also increase the overhead. Please make sure
that all nodes in your mesh use the same interval. The default value
is 1000 ms (1 second).
# echo 1000 > /proc/net/batman-adv/orig_interval
To deactivate batman, do:
# echo "" > /proc/net/batman-adv/interfaces
BATCTL
------
B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici-
pating in the virtual switch are completely transparent for all proto-
cols above layer 2. Therefore the common diagnosis tools do not work as
expected. To overcome these problems batctl was created. At the moment
the batctl contains ping, traceroute, tcpdump and interfaces to the
kernel module settings.
For more information, please see the manpage (man batctl).
batctl is available on http://www.open-mesh.net/
CONTACT
-------
Please send us comments, experiences, questions, anything :)
IRC: #batman on irc.freenode.org
Mailing-list: b.a.t.m.a.n@open-mesh.net
(subscription at https://list.open-mesh.net/mm/listinfo/b.a.t.m.a.n )
You can also contact the Authors:
Marek Lindner <lindner_marek@yahoo.de>
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>

View File

@ -0,0 +1,51 @@
=> proc interface
* implement new interface to add/delete interfaces and setting options
* /proc/sys/net/batman-adv/ as main folder
* in interfaces/ list every available interface of the host
* each interfaces/$iface/ contains the following files:
-> enable (def: 0) [add/remove this interface to batman-adv]
-> ogm_interval (def: 1000) [ogm interval of that interface]
-> context (def: bat0) [later we want to support multiple mesh instances via
-> bat0/bat1/bat2/..]
-> status (read-only) [outputs the interface status from batman's
-> perspective]
* in mesh/batX/ list every available mesh subnet
-> vis_server (def: 0) [enable/disable vis server for that mesh]
-> vis_data (read-only) [outputs the vis data in a raw format]
-> aggregate_ogm (def: 1) [enable/disable ogm aggregation for that mesh]
-> originators (read-only) [outputs the originator table]
-> transtable_global (read-only) [outputs the global translation table]
-> transtable_local (read-only) [outputs the local translation table]
=> vis "raw" data output
* the raw format shall replace dot draw / json to offer a neutral that can
* be converted
* the format (comma seperated entries):
-> "mac" -> mac address of an originator (each line begins with it)
-> "TQ mac value" -> src mac's link quality towards mac address
-> "HNA mac" -> HNA announced by source mac
-> "PRIMARY" -> this is a primary interface
-> "SEC mac" -> secondary mac address of source (requires preceeding
-> PRIMARY)
=> logging
* the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be
* unified to use printk
* LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the
* internal debug level has been raised
* the internal debug level can be modified using a module parameter (debug)
* or at run time via /sys/module/batman-adv/parameters/debug
* make use of printk %pM support instead of converting mac addresses
* manually
=> strip out all backward compatibility support to older kernels
(only found in compat.h)
=> fix checkpatch.pl errors
Please send all patches to:
Marek Lindner <lindner_marek@yahoo.de>
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Andrew Lunn <andrew@lunn.ch>
b.a.t.m.a.n@lists.open-mesh.net
Greg Kroah-Hartman <gregkh@suse.de>

View File

@ -0,0 +1,232 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "aggregation.h"
#include "send.h"
#include "routing.h"
/* calculate the size of the hna information for a given packet */
static int hna_len(struct batman_packet *batman_packet)
{
return batman_packet->num_hna * ETH_ALEN;
}
/* return true if new_packet can be aggregated with forw_packet */
static bool can_aggregate_with(struct batman_packet *new_batman_packet,
int packet_len,
unsigned long send_time,
bool directlink,
struct batman_if *if_incoming,
struct forw_packet *forw_packet)
{
struct batman_packet *batman_packet =
(struct batman_packet *)forw_packet->packet_buff;
int aggregated_bytes = forw_packet->packet_len + packet_len;
/**
* we can aggregate the current packet to this aggregated packet
* if:
*
* - the send time is within our MAX_AGGREGATION_MS time
* - the resulting packet wont be bigger than
* MAX_AGGREGATION_BYTES
*/
if (time_before(send_time, forw_packet->send_time) &&
(aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
/**
* check aggregation compatibility
* -> direct link packets are broadcasted on
* their interface only
* -> aggregate packet if the current packet is
* a "global" packet as well as the base
* packet
*/
/* packets without direct link flag and high TTL
* are flooded through the net */
if ((!directlink) &&
(!(batman_packet->flags & DIRECTLINK)) &&
(batman_packet->ttl != 1) &&
/* own packets originating non-primary
* interfaces leave only that interface */
((!forw_packet->own) ||
(forw_packet->if_incoming->if_num == 0)))
return true;
/* if the incoming packet is sent via this one
* interface only - we still can aggregate */
if ((directlink) &&
(new_batman_packet->ttl == 1) &&
(forw_packet->if_incoming == if_incoming))
return true;
}
return false;
}
/* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff,
int packet_len,
unsigned long send_time,
bool direct_link,
struct batman_if *if_incoming,
int own_packet)
{
struct forw_packet *forw_packet_aggr;
forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
if (!forw_packet_aggr)
return;
forw_packet_aggr->packet_buff = kmalloc(MAX_AGGREGATION_BYTES,
GFP_ATOMIC);
if (!forw_packet_aggr->packet_buff) {
kfree(forw_packet_aggr);
return;
}
INIT_HLIST_NODE(&forw_packet_aggr->list);
forw_packet_aggr->packet_len = packet_len;
memcpy(forw_packet_aggr->packet_buff,
packet_buff,
forw_packet_aggr->packet_len);
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->num_packets = 0;
forw_packet_aggr->direct_link_flags = 0;
forw_packet_aggr->send_time = send_time;
/* save packet direct link flag status */
if (direct_link)
forw_packet_aggr->direct_link_flags |= 1;
/* add new packet to packet list */
spin_lock(&forw_bat_list_lock);
hlist_add_head(&forw_packet_aggr->list, &forw_bat_list);
spin_unlock(&forw_bat_list_lock);
/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
send_outstanding_bat_packet);
queue_delayed_work(bat_event_workqueue,
&forw_packet_aggr->delayed_work,
send_time - jiffies);
}
/* aggregate a new packet into the existing aggregation */
static void aggregate(struct forw_packet *forw_packet_aggr,
unsigned char *packet_buff,
int packet_len,
bool direct_link)
{
memcpy((forw_packet_aggr->packet_buff + forw_packet_aggr->packet_len),
packet_buff, packet_len);
forw_packet_aggr->packet_len += packet_len;
forw_packet_aggr->num_packets++;
/* save packet direct link flag status */
if (direct_link)
forw_packet_aggr->direct_link_flags |=
(1 << forw_packet_aggr->num_packets);
}
void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
struct batman_if *if_incoming, char own_packet,
unsigned long send_time)
{
/**
* _aggr -> pointer to the packet we want to aggregate with
* _pos -> pointer to the position in the queue
*/
struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
struct hlist_node *tmp_node;
struct batman_packet *batman_packet =
(struct batman_packet *)packet_buff;
bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
/* find position for the packet in the forward queue */
spin_lock(&forw_bat_list_lock);
/* own packets are not to be aggregated */
if ((atomic_read(&aggregation_enabled)) && (!own_packet)) {
hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list,
list) {
if (can_aggregate_with(batman_packet,
packet_len,
send_time,
direct_link,
if_incoming,
forw_packet_pos)) {
forw_packet_aggr = forw_packet_pos;
break;
}
}
}
/* nothing to aggregate with - either aggregation disabled or no
* suitable aggregation packet found */
if (forw_packet_aggr == NULL) {
/* the following section can run without the lock */
spin_unlock(&forw_bat_list_lock);
new_aggregated_packet(packet_buff, packet_len,
send_time, direct_link,
if_incoming, own_packet);
} else {
aggregate(forw_packet_aggr,
packet_buff, packet_len,
direct_link);
spin_unlock(&forw_bat_list_lock);
}
}
/* unpack the aggregated packets and process them one by one */
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming)
{
struct batman_packet *batman_packet;
int buff_pos = 0;
unsigned char *hna_buff;
batman_packet = (struct batman_packet *)packet_buff;
while (aggregated_packet(buff_pos, packet_len,
batman_packet->num_hna)) {
/* network to host order for our 16bit seqno, and the
orig_interval. */
batman_packet->seqno = ntohs(batman_packet->seqno);
hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
receive_bat_packet(ethhdr, batman_packet,
hna_buff, hna_len(batman_packet),
if_incoming);
buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
batman_packet = (struct batman_packet *)
(packet_buff + buff_pos);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
/* is there another aggregated packet here? */
static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
{
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
}
void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
struct batman_if *if_outgoing, char own_packet,
unsigned long send_time);
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming);

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "bitarray.h"
#include "log.h"
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
uint16_t curr_seqno)
{
int16_t diff, word_offset, word_num;
diff = last_seqno - curr_seqno;
if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
return 0;
} else {
/* which word */
word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
/* which position in the selected word */
word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
if (seq_bits[word_num] & 1 << word_offset)
return 1;
else
return 0;
}
}
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n)
{
int32_t word_offset, word_num;
/* if too old, just drop it */
if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
return;
/* which word */
word_num = n / WORD_BIT_SIZE;
/* which position in the selected word */
word_offset = n % WORD_BIT_SIZE;
seq_bits[word_num] |= 1 << word_offset; /* turn the position on */
}
/* shift the packet array by n places. */
void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
{
int32_t word_offset, word_num;
int32_t i;
if (n <= 0)
return;
word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
for (i = NUM_WORDS - 1; i > word_num; i--) {
/* going from old to new, so we don't overwrite the data we copy
* from.
*
* left is high, right is low: FEDC BA98 7654 3210
* ^^ ^^
* vvvv
* ^^^^ = from, vvvvv =to, we'd have word_num==1 and
* word_offset==WORD_BIT_SIZE/2 ????? in this example.
* (=24 bits)
*
* our desired output would be: 9876 5432 1000 0000
* */
seq_bits[i] =
(seq_bits[i - word_num] << word_offset) +
/* take the lower port from the left half, shift it left
* to its final position */
(seq_bits[i - word_num - 1] >>
(WORD_BIT_SIZE-word_offset));
/* and the upper part of the right half and shift it left to
* it's position */
/* for our example that would be: word[0] = 9800 + 0076 =
* 9876 */
}
/* now for our last word, i==word_num, we only have the it's "left"
* half. that's the 1000 word in our example.*/
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
/* pad the rest with 0, if there is anything */
i--;
for (; i >= 0; i--)
seq_bits[i] = 0;
}
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
int8_t set_mark)
{
int i;
/* we already got a sequence number higher than this one, so we just
* mark it. this should wrap around the integer just fine */
if ((seq_num_diff < 0) && (seq_num_diff >= -TQ_LOCAL_WINDOW_SIZE)) {
if (set_mark)
bit_mark(seq_bits, -seq_num_diff);
return 0;
}
/* it seems we missed a lot of packets or the other host restarted */
if ((seq_num_diff > TQ_LOCAL_WINDOW_SIZE) ||
(seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) {
if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
debug_log(LOG_TYPE_BATMAN,
"We missed a lot of packets (%i) !\n",
seq_num_diff-1);
if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
debug_log(LOG_TYPE_BATMAN,
"Other host probably restarted !\n");
for (i = 0; i < NUM_WORDS; i++)
seq_bits[i] = 0;
if (set_mark)
seq_bits[0] = 1; /* we only have the latest packet */
} else {
bit_shift(seq_bits, seq_num_diff);
if (set_mark)
bit_mark(seq_bits, 0);
}
return 1;
}
/* count the hamming weight, how many good packets did we receive? just count
* the 1's. The inner loop uses the Kernighan algorithm, see
* http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
*/
int bit_packet_count(TYPE_OF_WORD *seq_bits)
{
int i, hamming = 0;
TYPE_OF_WORD word;
for (i = 0; i < NUM_WORDS; i++) {
word = seq_bits[i];
while (word) {
word &= word-1;
hamming++;
}
}
return hamming;
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
/* you should choose something big, if you don't want to waste cpu */
#define TYPE_OF_WORD unsigned long
#define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8)
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
uint16_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n);
/* shift the packet array by n places. */
void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n);
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
int8_t set_mark);
/* count the hamming weight, how many good packets did we receive? */
int bit_packet_count(TYPE_OF_WORD *seq_bits);

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*
* This file contains macros for maintaining compatibility with older versions
* of the Linux kernel.
*/
#include <linux/version.h> /* LINUX_VERSION_CODE */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
#define skb_set_network_header(_skb, _offset) \
do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0)
#define skb_reset_mac_header(_skb) \
do { (_skb)->mac.raw = (_skb)->data; } while (0)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
#define device_create(_cls, _parent, _devt, _device, _fmt) \
class_device_create(_cls, _parent, _devt, _device, _fmt)
#define device_destroy(_cls, _device) \
class_device_destroy(_cls, _device)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
#define device_create(_cls, _parent, _devt, _device, _fmt) \
device_create_drvdata(_cls, _parent, _devt, _device, _fmt)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
#define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
#define strict_strtoul(cp, base, res) \
({ \
int ret = 0; \
char *endp; \
*res = simple_strtoul(cp, &endp, base); \
if (cp == endp) \
ret = -EINVAL; \
ret; \
})
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */

View File

@ -0,0 +1,337 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "device.h"
#include "log.h"
#include "send.h"
#include "types.h"
#include "hash.h"
#include "compat.h"
static struct class *batman_class;
static int Major; /* Major number assigned to our device driver */
static const struct file_operations fops = {
.open = bat_device_open,
.release = bat_device_release,
.read = bat_device_read,
.write = bat_device_write,
.poll = bat_device_poll,
};
static struct device_client *device_client_hash[256];
void bat_device_init(void)
{
int i;
for (i = 0; i < 256; i++)
device_client_hash[i] = NULL;
}
int bat_device_setup(void)
{
int tmp_major;
if (Major)
return 1;
/* register our device - kernel assigns a free major number */
tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
if (tmp_major < 0) {
debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n",
tmp_major);
return 0;
}
batman_class = class_create(THIS_MODULE, "batman-adv");
if (IS_ERR(batman_class)) {
debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n");
return 0;
}
device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL,
"batman-adv");
Major = tmp_major;
return 1;
}
void bat_device_destroy(void)
{
if (!Major)
return;
device_destroy(batman_class, MKDEV(Major, 0));
class_destroy(batman_class);
/* Unregister the device */
unregister_chrdev(Major, DRIVER_DEVICE);
Major = 0;
}
int bat_device_open(struct inode *inode, struct file *file)
{
unsigned int i;
struct device_client *device_client;
device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL);
if (!device_client)
return -ENOMEM;
for (i = 0; i < 256; i++) {
if (!device_client_hash[i]) {
device_client_hash[i] = device_client;
break;
}
}
if (device_client_hash[i] != device_client) {
debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n");
kfree(device_client);
return -EXFULL;
}
INIT_LIST_HEAD(&device_client->queue_list);
device_client->queue_len = 0;
device_client->index = i;
device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock);
init_waitqueue_head(&device_client->queue_wait);
file->private_data = device_client;
inc_module_count();
return 0;
}
int bat_device_release(struct inode *inode, struct file *file)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct device_packet *device_packet;
struct list_head *list_pos, *list_pos_tmp;
spin_lock(&device_client->lock);
/* for all packets in the queue ... */
list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) {
device_packet = list_entry(list_pos,
struct device_packet, list);
list_del(list_pos);
kfree(device_packet);
}
device_client_hash[device_client->index] = NULL;
spin_unlock(&device_client->lock);
kfree(device_client);
dec_module_count();
return 0;
}
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct device_packet *device_packet;
int error;
if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0))
return -EAGAIN;
if ((!buf) || (count < sizeof(struct icmp_packet)))
return -EINVAL;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
error = wait_event_interruptible(device_client->queue_wait,
device_client->queue_len);
if (error)
return error;
spin_lock(&device_client->lock);
device_packet = list_first_entry(&device_client->queue_list,
struct device_packet, list);
list_del(&device_packet->list);
device_client->queue_len--;
spin_unlock(&device_client->lock);
error = __copy_to_user(buf, &device_packet->icmp_packet,
sizeof(struct icmp_packet));
kfree(device_packet);
if (error)
return error;
return sizeof(struct icmp_packet);
}
ssize_t bat_device_write(struct file *file, const char __user *buff,
size_t len, loff_t *off)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct icmp_packet icmp_packet;
struct orig_node *orig_node;
struct batman_if *batman_if;
if (len < sizeof(struct icmp_packet)) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n");
return -EINVAL;
}
if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet)))
return -EFAULT;
if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet)))
return -EFAULT;
if (icmp_packet.packet_type != BAT_ICMP) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
return -EINVAL;
}
if (icmp_packet.msg_type != ECHO_REQUEST) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
return -EINVAL;
}
icmp_packet.uid = device_client->index;
if (icmp_packet.version != COMPAT_VERSION) {
icmp_packet.msg_type = PARAMETER_PROBLEM;
icmp_packet.ttl = COMPAT_VERSION;
bat_device_add_packet(device_client, &icmp_packet);
goto out;
}
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto dst_unreach;
spin_lock(&orig_hash_lock);
orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
if (!orig_node)
goto unlock;
if (!orig_node->router)
goto unlock;
batman_if = orig_node->batman_if;
if (!batman_if)
goto unlock;
memcpy(icmp_packet.orig,
batman_if->net_dev->dev_addr,
ETH_ALEN);
send_raw_packet((unsigned char *)&icmp_packet,
sizeof(struct icmp_packet),
batman_if, orig_node->router->addr);
spin_unlock(&orig_hash_lock);
goto out;
unlock:
spin_unlock(&orig_hash_lock);
dst_unreach:
icmp_packet.msg_type = DESTINATION_UNREACHABLE;
bat_device_add_packet(device_client, &icmp_packet);
out:
return len;
}
unsigned int bat_device_poll(struct file *file, poll_table *wait)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
poll_wait(file, &device_client->queue_wait, wait);
if (device_client->queue_len > 0)
return POLLIN | POLLRDNORM;
return 0;
}
void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet)
{
struct device_packet *device_packet;
device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
if (!device_packet)
return;
INIT_LIST_HEAD(&device_packet->list);
memcpy(&device_packet->icmp_packet, icmp_packet,
sizeof(struct icmp_packet));
spin_lock(&device_client->lock);
/* while waiting for the lock the device_client could have been
* deleted */
if (!device_client_hash[icmp_packet->uid]) {
spin_unlock(&device_client->lock);
kfree(device_packet);
return;
}
list_add_tail(&device_packet->list, &device_client->queue_list);
device_client->queue_len++;
if (device_client->queue_len > 100) {
device_packet = list_first_entry(&device_client->queue_list,
struct device_packet, list);
list_del(&device_packet->list);
kfree(device_packet);
device_client->queue_len--;
}
spin_unlock(&device_client->lock);
wake_up(&device_client->queue_wait);
}
void bat_device_receive_packet(struct icmp_packet *icmp_packet)
{
struct device_client *hash = device_client_hash[icmp_packet->uid];
if (hash)
bat_device_add_packet(hash, icmp_packet);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
void bat_device_init(void);
int bat_device_setup(void);
void bat_device_destroy(void);
int bat_device_open(struct inode *inode, struct file *file);
int bat_device_release(struct inode *inode, struct file *file);
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos);
ssize_t bat_device_write(struct file *file, const char __user *buff,
size_t len, loff_t *off);
unsigned int bat_device_poll(struct file *file, poll_table *wait);
void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet);
void bat_device_receive_packet(struct icmp_packet *icmp_packet);

View File

@ -0,0 +1,451 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "hard-interface.h"
#include "log.h"
#include "soft-interface.h"
#include "send.h"
#include "translation-table.h"
#include "routing.h"
#include "hash.h"
#include "compat.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
static char avail_ifs;
static char active_ifs;
static void hardif_free_interface(struct rcu_head *rcu);
static struct batman_if *get_batman_if_by_name(char *name)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (strncmp(batman_if->dev, name, IFNAMSIZ) == 0)
goto out;
}
batman_if = NULL;
out:
rcu_read_unlock();
return batman_if;
}
int hardif_min_mtu(void)
{
struct batman_if *batman_if;
/* allow big frames if all devices are capable to do so
* (have MTU > 1500 + BAT_HEADER_LEN) */
int min_mtu = ETH_DATA_LEN;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->if_active == IF_ACTIVE) ||
(batman_if->if_active == IF_TO_BE_ACTIVATED))
min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN,
min_mtu);
}
rcu_read_unlock();
return min_mtu;
}
static void check_known_mac_addr(uint8_t *addr)
{
struct batman_if *batman_if;
char mac_string[ETH_STR_LEN];
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->if_active != IF_ACTIVE) &&
(batman_if->if_active != IF_TO_BE_ACTIVATED))
continue;
if (!compare_orig(batman_if->net_dev->dev_addr, addr))
continue;
addr_to_string(mac_string, addr);
debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n",
mac_string, batman_if->dev);
debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n");
}
rcu_read_unlock();
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
void update_min_mtu(void)
{
int min_mtu;
min_mtu = hardif_min_mtu();
if (soft_device->mtu != min_mtu)
soft_device->mtu = min_mtu;
}
/* checks if the interface is up. (returns 1 if it is) */
static int hardif_is_interface_up(char *dev)
{
struct net_device *net_dev;
/**
* if we already have an interface in our interface list and
* the current interface is not the primary interface and
* the primary interface is not up and
* the primary interface has never been up - don't activate any
* secondary interface !
*/
rcu_read_lock();
if ((!list_empty(&if_list)) &&
strncmp(((struct batman_if *)if_list.next)->dev, dev, IFNAMSIZ) &&
!(((struct batman_if *)if_list.next)->if_active == IF_ACTIVE) &&
!(((struct batman_if *)if_list.next)->if_active == IF_TO_BE_ACTIVATED) &&
(!main_if_was_up())) {
rcu_read_unlock();
goto end;
}
rcu_read_unlock();
#ifdef __NET_NET_NAMESPACE_H
net_dev = dev_get_by_name(&init_net, dev);
#else
net_dev = dev_get_by_name(dev);
#endif
if (!net_dev)
goto end;
if (!(net_dev->flags & IFF_UP))
goto failure;
dev_put(net_dev);
return 1;
failure:
dev_put(net_dev);
end:
return 0;
}
/* deactivates the interface. */
void hardif_deactivate_interface(struct batman_if *batman_if)
{
if (batman_if->if_active != IF_ACTIVE)
return;
if (batman_if->raw_sock)
sock_release(batman_if->raw_sock);
/**
* batman_if->net_dev has been acquired by dev_get_by_name() in
* proc_interfaces_write() and has to be unreferenced.
*/
if (batman_if->net_dev)
dev_put(batman_if->net_dev);
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
batman_if->if_active = IF_INACTIVE;
active_ifs--;
debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n",
batman_if->dev);
}
/* (re)activate given interface. */
static void hardif_activate_interface(struct batman_if *batman_if)
{
struct sockaddr_ll bind_addr;
int retval;
if (batman_if->if_active != IF_INACTIVE)
return;
#ifdef __NET_NET_NAMESPACE_H
batman_if->net_dev = dev_get_by_name(&init_net, batman_if->dev);
#else
batman_if->net_dev = dev_get_by_name(batman_if->dev);
#endif
if (!batman_if->net_dev)
goto dev_err;
retval = sock_create_kern(PF_PACKET, SOCK_RAW,
__constant_htons(ETH_P_BATMAN),
&batman_if->raw_sock);
if (retval < 0) {
debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n",
retval);
goto sock_err;
}
bind_addr.sll_family = AF_PACKET;
bind_addr.sll_ifindex = batman_if->net_dev->ifindex;
bind_addr.sll_protocol = 0; /* is set by the kernel */
retval = kernel_bind(batman_if->raw_sock,
(struct sockaddr *)&bind_addr, sizeof(bind_addr));
if (retval < 0) {
debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n",
retval);
goto bind_err;
}
check_known_mac_addr(batman_if->net_dev->dev_addr);
batman_if->raw_sock->sk->sk_user_data =
batman_if->raw_sock->sk->sk_data_ready;
batman_if->raw_sock->sk->sk_data_ready = batman_data_ready;
addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr);
memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
batman_if->net_dev->dev_addr, ETH_ALEN);
memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
batman_if->net_dev->dev_addr, ETH_ALEN);
batman_if->if_active = IF_TO_BE_ACTIVATED;
active_ifs++;
/* save the mac address if it is our primary interface */
if (batman_if->if_num == 0)
set_main_if_addr(batman_if->net_dev->dev_addr);
debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n",
batman_if->dev);
return;
bind_err:
sock_release(batman_if->raw_sock);
sock_err:
dev_put(batman_if->net_dev);
dev_err:
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
}
static void hardif_free_interface(struct rcu_head *rcu)
{
struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu);
kfree(batman_if->packet_buff);
kfree(batman_if->dev);
kfree(batman_if);
}
/**
* called by
* - echo '' > /proc/.../interfaces
* - modprobe -r batman-adv-core
*/
/* removes and frees all interfaces */
void hardif_remove_interfaces(void)
{
struct batman_if *batman_if = NULL;
avail_ifs = 0;
/* no lock needed - we don't delete somewhere else */
list_for_each_entry(batman_if, &if_list, list) {
list_del_rcu(&batman_if->list);
/* first deactivate interface */
if (batman_if->if_active != IF_INACTIVE)
hardif_deactivate_interface(batman_if);
call_rcu(&batman_if->rcu, hardif_free_interface);
}
}
static int resize_orig(struct orig_node *orig_node, int if_num)
{
void *data_ptr;
data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr) {
debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own,
if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS);
kfree(orig_node->bcast_own);
orig_node->bcast_own = data_ptr;
data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own_sum, if_num * sizeof(uint8_t));
kfree(orig_node->bcast_own_sum);
orig_node->bcast_own_sum = data_ptr;
return 0;
}
/* adds an interface the interface list and activate it, if possible */
int hardif_add_interface(char *dev, int if_num)
{
struct batman_if *batman_if;
struct batman_packet *batman_packet;
struct orig_node *orig_node;
struct hash_it_t *hashit = NULL;
batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL);
if (!batman_if) {
debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev);
return -1;
}
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
if ((if_num == 0) && (num_hna > 0))
batman_if->packet_len = BAT_PACKET_LEN + num_hna * ETH_ALEN;
else
batman_if->packet_len = BAT_PACKET_LEN;
batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL);
if (!batman_if->packet_buff) {
debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev);
goto out;
}
batman_if->if_num = if_num;
batman_if->dev = dev;
batman_if->if_active = IF_INACTIVE;
INIT_RCU_HEAD(&batman_if->rcu);
debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev);
avail_ifs++;
INIT_LIST_HEAD(&batman_if->list);
batman_packet = (struct batman_packet *)(batman_if->packet_buff);
batman_packet->packet_type = BAT_PACKET;
batman_packet->version = COMPAT_VERSION;
batman_packet->flags = 0x00;
batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL);
batman_packet->flags = 0;
batman_packet->tq = TQ_MAX_VALUE;
batman_packet->num_hna = 0;
if (batman_if->packet_len != BAT_PACKET_LEN) {
unsigned char *hna_buff;
int hna_len;
hna_buff = batman_if->packet_buff + BAT_PACKET_LEN;
hna_len = batman_if->packet_len - BAT_PACKET_LEN;
batman_packet->num_hna = hna_local_fill_buffer(hna_buff,
hna_len);
}
atomic_set(&batman_if->seqno, 1);
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock(&orig_hash_lock);
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
if (resize_orig(orig_node, if_num) == -1) {
spin_unlock(&orig_hash_lock);
goto out;
}
}
spin_unlock(&orig_hash_lock);
if (!hardif_is_interface_up(batman_if->dev))
debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev);
else
hardif_activate_interface(batman_if);
list_add_tail_rcu(&batman_if->list, &if_list);
/* begin sending originator messages on that interface */
schedule_own_packet(batman_if);
return 1;
out:
if (batman_if->packet_buff)
kfree(batman_if->packet_buff);
kfree(batman_if);
kfree(dev);
return -1;
}
char hardif_get_active_if_num(void)
{
return active_ifs;
}
static int hard_if_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
struct batman_if *batman_if = get_batman_if_by_name(dev->name);
if (!batman_if)
goto out;
switch (event) {
case NETDEV_GOING_DOWN:
case NETDEV_DOWN:
case NETDEV_UNREGISTER:
hardif_deactivate_interface(batman_if);
break;
case NETDEV_UP:
hardif_activate_interface(batman_if);
if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
(hardif_get_active_if_num() > 0)) {
activate_module();
}
break;
/* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */
default:
/* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */
break;
};
update_min_mtu();
out:
return NOTIFY_DONE;
}
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#define IF_INACTIVE 0
#define IF_ACTIVE 1
/* #define IF_TO_BE_DEACTIVATED 2 - not needed anymore */
#define IF_TO_BE_ACTIVATED 3
extern struct notifier_block hard_if_notifier;
void hardif_remove_interfaces(void);
int hardif_add_interface(char *dev, int if_num);
void hardif_deactivate_interface(struct batman_if *batman_if);
char hardif_get_active_if_num(void);
void hardif_check_interfaces_status(void);
void hardif_check_interfaces_status_wq(struct work_struct *work);
int hardif_min_mtu(void);
void update_min_mtu(void);

View File

@ -0,0 +1,313 @@
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "hash.h"
/* clears the hash */
void hash_init(struct hashtable_t *hash)
{
int i;
hash->elements = 0;
for (i = 0 ; i < hash->size; i++)
hash->table[i] = NULL;
}
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash. if you don't remove the
* elements, memory might be leaked. */
void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb)
{
struct element_t *bucket, *last_bucket;
int i;
for (i = 0; i < hash->size; i++) {
bucket = hash->table[i];
while (bucket != NULL) {
if (free_cb != NULL)
free_cb(bucket->data);
last_bucket = bucket;
bucket = bucket->next;
kfree(last_bucket);
}
}
hash_destroy(hash);
}
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash)
{
kfree(hash->table);
kfree(hash);
}
/* iterate though the hash. first element is selected with iter_in NULL. use
* the returned iterator to access the elements until hash_it_t returns NULL. */
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
struct hash_it_t *iter_in)
{
struct hash_it_t *iter;
if (!hash)
return NULL;
if (iter_in == NULL) {
iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC);
iter->index = -1;
iter->bucket = NULL;
iter->prev_bucket = NULL;
} else {
iter = iter_in;
}
/* sanity checks first (if our bucket got deleted in the last
* iteration): */
if (iter->bucket != NULL) {
if (iter->first_bucket != NULL) {
/* we're on the first element and it got removed after
* the last iteration. */
if ((*iter->first_bucket) != iter->bucket) {
/* there are still other elements in the list */
if ((*iter->first_bucket) != NULL) {
iter->prev_bucket = NULL;
iter->bucket = (*iter->first_bucket);
iter->first_bucket =
&hash->table[iter->index];
return iter;
} else {
iter->bucket = NULL;
}
}
} else if (iter->prev_bucket != NULL) {
/*
* we're not on the first element, and the bucket got
* removed after the last iteration. the last bucket's
* next pointer is not pointing to our actual bucket
* anymore. select the next.
*/
if (iter->prev_bucket->next != iter->bucket)
iter->bucket = iter->prev_bucket;
}
}
/* now as we are sane, select the next one if there is some */
if (iter->bucket != NULL) {
if (iter->bucket->next != NULL) {
iter->prev_bucket = iter->bucket;
iter->bucket = iter->bucket->next;
iter->first_bucket = NULL;
return iter;
}
}
/* if not returned yet, we've reached the last one on the index and have
* to search forward */
iter->index++;
/* go through the entries of the hash table */
while (iter->index < hash->size) {
if ((hash->table[iter->index]) != NULL) {
iter->prev_bucket = NULL;
iter->bucket = hash->table[iter->index];
iter->first_bucket = &hash->table[iter->index];
return iter;
} else {
iter->index++;
}
}
/* nothing to iterate over anymore */
kfree(iter);
return NULL;
}
/* allocates and clears the hash */
struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
hashdata_choose_cb choose)
{
struct hashtable_t *hash;
hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
if (hash == NULL)
return NULL;
hash->size = size;
hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
if (hash->table == NULL) {
kfree(hash);
return NULL;
}
hash_init(hash);
hash->compare = compare;
hash->choose = choose;
return hash;
}
/* adds data to the hashtable. returns 0 on success, -1 on error */
int hash_add(struct hashtable_t *hash, void *data)
{
int index;
struct element_t *bucket, *prev_bucket = NULL;
if (!hash)
return -1;
index = hash->choose(data, hash->size);
bucket = hash->table[index];
while (bucket != NULL) {
if (hash->compare(bucket->data, data))
return -1;
prev_bucket = bucket;
bucket = bucket->next;
}
/* found the tail of the list, add new element */
bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
if (bucket == NULL)
return -1;
bucket->data = data;
bucket->next = NULL;
/* and link it */
if (prev_bucket == NULL)
hash->table[index] = bucket;
else
prev_bucket->next = bucket;
hash->elements++;
return 0;
}
/* finds data, based on the key in keydata. returns the found data on success,
* or NULL on error */
void *hash_find(struct hashtable_t *hash, void *keydata)
{
int index;
struct element_t *bucket;
if (!hash)
return NULL;
index = hash->choose(keydata , hash->size);
bucket = hash->table[index];
while (bucket != NULL) {
if (hash->compare(bucket->data, keydata))
return bucket->data;
bucket = bucket->next;
}
return NULL;
}
/* remove bucket (this might be used in hash_iterate() if you already found the
* bucket you want to delete and don't need the overhead to find it again with
* hash_remove(). But usually, you don't want to use this function, as it
* fiddles with hash-internals. */
void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
{
void *data_save;
data_save = hash_it_t->bucket->data;
if (hash_it_t->prev_bucket != NULL)
hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
else if (hash_it_t->first_bucket != NULL)
(*hash_it_t->first_bucket) = hash_it_t->bucket->next;
kfree(hash_it_t->bucket);
hash->elements--;
return data_save;
}
/* removes data from hash, if found. returns pointer do data on success, so you
* can remove the used structure yourself, or NULL on error . data could be the
* structure you use with just the key filled, we just need the key for
* comparing. */
void *hash_remove(struct hashtable_t *hash, void *data)
{
struct hash_it_t hash_it_t;
hash_it_t.index = hash->choose(data, hash->size);
hash_it_t.bucket = hash->table[hash_it_t.index];
hash_it_t.prev_bucket = NULL;
while (hash_it_t.bucket != NULL) {
if (hash->compare(hash_it_t.bucket->data, data)) {
hash_it_t.first_bucket =
(hash_it_t.bucket ==
hash->table[hash_it_t.index] ?
&hash->table[hash_it_t.index] : NULL);
return hash_remove_bucket(hash, &hash_it_t);
}
hash_it_t.prev_bucket = hash_it_t.bucket;
hash_it_t.bucket = hash_it_t.bucket->next;
}
return NULL;
}
/* resize the hash, returns the pointer to the new hash or NULL on
* error. removes the old hash on success. */
struct hashtable_t *hash_resize(struct hashtable_t *hash, int size)
{
struct hashtable_t *new_hash;
struct element_t *bucket;
int i;
/* initialize a new hash with the new size */
new_hash = hash_new(size, hash->compare, hash->choose);
if (new_hash == NULL)
return NULL;
/* copy the elements */
for (i = 0; i < hash->size; i++) {
bucket = hash->table[i];
while (bucket != NULL) {
hash_add(new_hash, bucket->data);
bucket = bucket->next;
}
}
/* remove hash and eventual overflow buckets but not the content
* itself. */
hash_delete(hash, NULL);
return new_hash;
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#ifndef _BATMAN_HASH_H
#define _BATMAN_HASH_H
typedef int (*hashdata_compare_cb)(void *, void *);
typedef int (*hashdata_choose_cb)(void *, int);
typedef void (*hashdata_free_cb)(void *);
struct element_t {
void *data; /* pointer to the data */
struct element_t *next; /* overflow bucket pointer */
};
struct hash_it_t {
int index;
struct element_t *bucket;
struct element_t *prev_bucket;
struct element_t **first_bucket;
};
struct hashtable_t {
struct element_t **table; /* the hashtable itself, with the buckets */
int elements; /* number of elements registered */
int size; /* size of hashtable */
hashdata_compare_cb compare;/* callback to a compare function. should
* compare 2 element datas for their keys,
* return 0 if same and not 0 if not
* same */
hashdata_choose_cb choose; /* the hashfunction, should return an index
* based on the key in the data of the first
* argument and the size the second */
};
/* clears the hash */
void hash_init(struct hashtable_t *hash);
/* allocates and clears the hash */
struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
hashdata_choose_cb choose);
/* remove bucket (this might be used in hash_iterate() if you already found the
* bucket you want to delete and don't need the overhead to find it again with
* hash_remove(). But usually, you don't want to use this function, as it
* fiddles with hash-internals. */
void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t);
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash. if you don't remove the
* elements, memory might be leaked. */
void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb);
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash);
/* adds data to the hashtable. returns 0 on success, -1 on error */
int hash_add(struct hashtable_t *hash, void *data);
/* removes data from hash, if found. returns pointer do data on success, so you
* can remove the used structure yourself, or NULL on error . data could be the
* structure you use with just the key filled, we just need the key for
* comparing. */
void *hash_remove(struct hashtable_t *hash, void *data);
/* finds data, based on the key in keydata. returns the found data on success,
* or NULL on error */
void *hash_find(struct hashtable_t *hash, void *keydata);
/* resize the hash, returns the pointer to the new hash or NULL on
* error. removes the old hash on success */
struct hashtable_t *hash_resize(struct hashtable_t *hash, int size);
/* iterate though the hash. first element is selected with iter_in NULL. use
* the returned iterator to access the elements until hash_it_t returns NULL. */
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
struct hash_it_t *iter_in);
/* print the hash table for debugging */
void hash_debug(struct hashtable_t *hash);
#endif

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "log.h"
#define LOG_BUF_MASK (log_buf_len-1)
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static char log_buf[LOG_BUF_LEN];
static int log_buf_len = LOG_BUF_LEN;
static unsigned long log_start;
static unsigned long log_end;
uint8_t log_level;
static DEFINE_SPINLOCK(logbuf_lock);
const struct file_operations proc_log_operations = {
.open = log_open,
.release = log_release,
.read = log_read,
.write = log_write,
.poll = log_poll,
};
static DECLARE_WAIT_QUEUE_HEAD(log_wait);
static void emit_log_char(char c)
{
LOG_BUF(log_end) = c;
log_end++;
if (log_end - log_start > log_buf_len)
log_start = log_end - log_buf_len;
}
static int fdebug_log(char *fmt, ...)
{
int printed_len;
char *p;
va_list args;
static char debug_log_buf[256];
unsigned long flags;
spin_lock_irqsave(&logbuf_lock, flags);
va_start(args, fmt);
printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt,
args);
va_end(args);
for (p = debug_log_buf; *p != 0; p++)
emit_log_char(*p);
spin_unlock_irqrestore(&logbuf_lock, flags);
wake_up(&log_wait);
return 0;
}
int debug_log(int type, char *fmt, ...)
{
va_list args;
int retval = 0;
char tmp_log_buf[256];
/* only critical information get into the official kernel log */
if (type == LOG_TYPE_CRIT) {
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
printk(KERN_ERR "batman-adv: %s", tmp_log_buf);
va_end(args);
}
if ((type == LOG_TYPE_CRIT) || (log_level & type)) {
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf);
va_end(args);
}
return retval;
}
int log_open(struct inode *inode, struct file *file)
{
inc_module_count();
return 0;
}
int log_release(struct inode *inode, struct file *file)
{
dec_module_count();
return 0;
}
ssize_t log_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
int error, i = 0;
char c;
unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start))
return -EAGAIN;
if ((!buf) || (count < 0))
return -EINVAL;
if (count == 0)
return 0;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
error = wait_event_interruptible(log_wait, (log_start - log_end));
if (error)
return error;
spin_lock_irqsave(&logbuf_lock, flags);
while ((!error) && (log_start != log_end) && (i < count)) {
c = LOG_BUF(log_start);
log_start++;
spin_unlock_irqrestore(&logbuf_lock, flags);
error = __put_user(c, buf);
spin_lock_irqsave(&logbuf_lock, flags);
buf++;
i++;
}
spin_unlock_irqrestore(&logbuf_lock, flags);
if (!error)
return i;
return error;
}
ssize_t log_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
return count;
}
unsigned int log_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &log_wait, wait);
if (log_end - log_start)
return POLLIN | POLLRDNORM;
return 0;
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
extern const struct file_operations proc_log_operations;
extern uint8_t log_level;
int debug_log(int type, char *fmt, ...);
int log_open(struct inode *inode, struct file *file);
int log_release(struct inode *inode, struct file *file);
ssize_t log_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos);
ssize_t log_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos);
unsigned int log_poll(struct file *file, poll_table *wait);

View File

@ -0,0 +1,286 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "proc.h"
#include "log.h"
#include "routing.h"
#include "send.h"
#include "soft-interface.h"
#include "device.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "vis.h"
#include "hash.h"
#include "compat.h"
struct list_head if_list;
struct hlist_head forw_bat_list;
struct hlist_head forw_bcast_list;
struct hashtable_t *orig_hash;
DEFINE_SPINLOCK(orig_hash_lock);
DEFINE_SPINLOCK(forw_bat_list_lock);
DEFINE_SPINLOCK(forw_bcast_list_lock);
atomic_t originator_interval;
atomic_t vis_interval;
atomic_t aggregation_enabled;
int16_t num_hna;
int16_t num_ifs;
struct net_device *soft_device;
static struct task_struct *kthread_task;
unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
atomic_t module_state;
struct workqueue_struct *bat_event_workqueue;
int init_module(void)
{
int retval;
INIT_LIST_HEAD(&if_list);
INIT_HLIST_HEAD(&forw_bat_list);
INIT_HLIST_HEAD(&forw_bcast_list);
atomic_set(&module_state, MODULE_INACTIVE);
atomic_set(&originator_interval, 1000);
atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
* for debugging now. */
atomic_set(&aggregation_enabled, 1);
/* the name should not be longer than 10 chars - see
* http://lwn.net/Articles/23634/ */
bat_event_workqueue = create_singlethread_workqueue("bat_events");
if (!bat_event_workqueue)
return -ENOMEM;
retval = setup_procfs();
if (retval < 0)
return retval;
bat_device_init();
/* initialize layer 2 interface */
soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d",
interface_setup);
if (!soft_device) {
debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n");
goto end;
}
retval = register_netdev(soft_device);
if (retval < 0) {
debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval);
goto free_soft_device;
}
register_netdevice_notifier(&hard_if_notifier);
debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n",
SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
return 0;
free_soft_device:
free_netdev(soft_device);
soft_device = NULL;
end:
return -ENOMEM;
}
void cleanup_module(void)
{
shutdown_module();
if (soft_device) {
unregister_netdev(soft_device);
soft_device = NULL;
}
unregister_netdevice_notifier(&hard_if_notifier);
cleanup_procfs();
destroy_workqueue(bat_event_workqueue);
bat_event_workqueue = NULL;
}
/* activates the module, creates bat device, starts timer ... */
void activate_module(void)
{
if (originator_init() < 1)
goto err;
if (hna_local_init() < 1)
goto err;
if (hna_global_init() < 1)
goto err;
hna_local_add(soft_device->dev_addr);
if (bat_device_setup() < 1)
goto end;
if (vis_init() < 1)
goto err;
/* (re)start kernel thread for packet processing */
if (!kthread_task) {
kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv");
if (IS_ERR(kthread_task)) {
debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n");
kthread_task = NULL;
}
}
update_min_mtu();
atomic_set(&module_state, MODULE_ACTIVE);
goto end;
err:
debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n");
shutdown_module();
end:
return;
}
/* shuts down the whole module.*/
void shutdown_module(void)
{
atomic_set(&module_state, MODULE_DEACTIVATING);
purge_outstanding_packets();
flush_workqueue(bat_event_workqueue);
vis_quit();
/* deactivate kernel thread for packet processing (if running) */
if (kthread_task) {
atomic_set(&exit_cond, 1);
wake_up_interruptible(&thread_wait);
kthread_stop(kthread_task);
kthread_task = NULL;
}
originator_free();
hna_local_free();
hna_global_free();
synchronize_net();
bat_device_destroy();
hardif_remove_interfaces();
synchronize_rcu();
atomic_set(&module_state, MODULE_INACTIVE);
}
void inc_module_count(void)
{
try_module_get(THIS_MODULE);
}
void dec_module_count(void)
{
module_put(THIS_MODULE);
}
int addr_to_string(char *buff, uint8_t *addr)
{
return sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
/* returns 1 if they are the same originator */
int compare_orig(void *data1, void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
int choose_orig(void *data, int32_t size)
{
unsigned char *key = data;
uint32_t hash = 0;
size_t i;
for (i = 0; i < 6; i++) {
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash % size;
}
int is_my_mac(uint8_t *addr)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->net_dev) &&
(compare_orig(batman_if->net_dev->dev_addr, addr))) {
rcu_read_unlock();
return 1;
}
}
rcu_read_unlock();
return 0;
}
int is_bcast(uint8_t *addr)
{
return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
}
int is_mcast(uint8_t *addr)
{
return *addr & 0x01;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
#ifdef REVISION_VERSION
MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
#else
MODULE_VERSION(SOURCE_VERSION);
#endif

View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
/* Kernel Programming */
#define LINUX
#define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
#define SOURCE_VERSION "0.2.1-beta"
/* B.A.T.M.A.N. parameters */
#define TQ_MAX_VALUE 255
#define JITTER 20
#define TTL 50 /* Time To Live of broadcast messages */
#define MAX_ADDR 16 /* number of interfaces which can be added to
* batman. */
#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
* valid packet comes in -> TODO: check
* influence on TQ_LOCAL_WINDOW_SIZE */
#define LOCAL_HNA_TIMEOUT 3600000
#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
* messages in squence numbers (should be a
* multiple of our word size) */
#define TQ_GLOBAL_WINDOW_SIZE 5
#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define TQ_TOTAL_BIDRECT_LIMIT 1
#define TQ_HOP_PENALTY 10
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define PACKBUFF_SIZE 2000
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
#define ETH_STR_LEN 20
#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
* change the size of
* forw_packet->direct_link_flags */
#define MAX_AGGREGATION_MS 100
#define MODULE_INACTIVE 0
#define MODULE_ACTIVE 1
#define MODULE_DEACTIVATING 2
/*
* Logging
*/
#define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as
* blocked sockets / failed packet delivery /
* programming errors */
#define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user
* input / damaged packets / etc */
#define LOG_TYPE_NOTICE 2 /* notice information for new interfaces /
* changed settings / new originators / etc */
#define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding /
* broadcasting / etc */
#define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */
#define LOG_TYPE_CRIT_NAME "critical"
#define LOG_TYPE_WARN_NAME "warnings"
#define LOG_TYPE_NOTICE_NAME "notices"
#define LOG_TYPE_BATMAN_NAME "batman"
#define LOG_TYPE_ROUTES_NAME "routes"
/*
* Vis
*/
/* #define VIS_SUBCLUSTERS_DISABLED */
/*
* Kernel headers
*/
#include <linux/mutex.h> /* mutex */
#include <linux/module.h> /* needed by all modules */
#include <linux/netdevice.h> /* netdevice */
#include <linux/if_ether.h> /* ethernet header */
#include <linux/poll.h> /* poll_table */
#include <linux/kthread.h> /* kernel threads */
#include <linux/pkt_sched.h> /* schedule types */
#include <linux/workqueue.h> /* workqueue */
#include <net/sock.h> /* struct sock */
#include <linux/jiffies.h>
#include "types.h"
#ifndef REVISION_VERSION
#define REVISION_VERSION_STR ""
#else
#define REVISION_VERSION_STR " "REVISION_VERSION
#endif
extern struct list_head if_list;
extern struct hlist_head forw_bat_list;
extern struct hlist_head forw_bcast_list;
extern struct hashtable_t *orig_hash;
extern spinlock_t orig_hash_lock;
extern spinlock_t forw_bat_list_lock;
extern spinlock_t forw_bcast_list_lock;
extern atomic_t originator_interval;
extern atomic_t vis_interval;
extern atomic_t aggregation_enabled;
extern int16_t num_hna;
extern int16_t num_ifs;
extern struct net_device *soft_device;
extern unsigned char broadcastAddr[];
extern atomic_t module_state;
extern struct workqueue_struct *bat_event_workqueue;
void activate_module(void);
void shutdown_module(void);
void inc_module_count(void);
void dec_module_count(void);
int addr_to_string(char *buff, uint8_t *addr);
int compare_orig(void *data1, void *data2);
int choose_orig(void *data, int32_t size);
int is_my_mac(uint8_t *addr);
int is_bcast(uint8_t *addr);
int is_mcast(uint8_t *addr);

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
#define BAT_PACKET 0x01
#define BAT_ICMP 0x02
#define BAT_UNICAST 0x03
#define BAT_BCAST 0x04
#define BAT_VIS 0x05
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 8
#define DIRECTLINK 0x40
#define VIS_SERVER 0x20
/* ICMP message types */
#define ECHO_REPLY 0
#define DESTINATION_UNREACHABLE 3
#define ECHO_REQUEST 8
#define TTL_EXCEEDED 11
#define PARAMETER_PROBLEM 12
/* vis defines */
#define VIS_TYPE_SERVER_SYNC 0
#define VIS_TYPE_CLIENT_UPDATE 1
struct batman_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint8_t tq;
uint16_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
uint8_t ttl;
uint8_t num_hna;
} __attribute__((packed));
#define BAT_PACKET_LEN sizeof(struct batman_packet)
struct icmp_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
} __attribute__((packed));
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t dest[6];
uint8_t ttl;
} __attribute__((packed));
struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
uint16_t seqno;
} __attribute__((packed));
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t vis_type; /* which type of vis-participant sent this? */
uint8_t seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
uint8_t ttl; /* TTL */
uint8_t vis_orig[6]; /* originator that informs about its
* neighbours */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));

View File

@ -0,0 +1,950 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "proc.h"
#include "log.h"
#include "routing.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "hash.h"
#include "vis.h"
#include "compat.h"
static uint8_t vis_format = DOT_DRAW;
static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
static struct proc_dir_entry *proc_log_file, *proc_log_level_file;
static struct proc_dir_entry *proc_transt_local_file;
static struct proc_dir_entry *proc_transt_global_file;
static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file;
static struct proc_dir_entry *proc_aggr_file;
static int proc_interfaces_read(struct seq_file *seq, void *offset)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
seq_printf(seq, "[%8s] %s %s \n",
(batman_if->if_active == IF_ACTIVE ?
"active" : "inactive"),
batman_if->dev,
(batman_if->if_active == IF_ACTIVE ?
batman_if->addr_str : " "));
}
rcu_read_unlock();
return 0;
}
static int proc_interfaces_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_interfaces_read, NULL);
}
static ssize_t proc_interfaces_write(struct file *instance,
const char __user *userbuffer,
size_t count, loff_t *data)
{
char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
int not_copied = 0, if_num = 0;
struct batman_if *batman_if = NULL;
if_string = kmalloc(count, GFP_KERNEL);
if (!if_string)
return -ENOMEM;
if (count > IFNAMSIZ - 1) {
debug_log(LOG_TYPE_WARN,
"Can't add interface: device name is too long\n");
goto end;
}
not_copied = copy_from_user(if_string, userbuffer, count);
if_string[count - not_copied - 1] = 0;
colon_ptr = strchr(if_string, ':');
if (colon_ptr)
*colon_ptr = 0;
if (!colon_ptr) {
cr_ptr = strchr(if_string, '\n');
if (cr_ptr)
*cr_ptr = 0;
}
if (strlen(if_string) == 0) {
shutdown_module();
num_ifs = 0;
goto end;
}
/* add interface */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (strncmp(batman_if->dev, if_string, count) == 0) {
debug_log(LOG_TYPE_WARN, "Given interface is already active: %s\n", if_string);
rcu_read_unlock();
goto end;
}
if_num++;
}
rcu_read_unlock();
hardif_add_interface(if_string, if_num);
if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
(hardif_get_active_if_num() > 0))
activate_module();
rcu_read_lock();
if (list_empty(&if_list)) {
rcu_read_unlock();
goto end;
}
rcu_read_unlock();
num_ifs = if_num + 1;
return count;
end:
kfree(if_string);
return count;
}
static int proc_orig_interval_read(struct seq_file *seq, void *offset)
{
seq_printf(seq, "%i\n", atomic_read(&originator_interval));
return 0;
}
static ssize_t proc_orig_interval_write(struct file *file,
const char __user *buffer,
size_t count, loff_t *ppos)
{
char *interval_string;
int not_copied = 0;
unsigned long originator_interval_tmp;
int retval;
interval_string = kmalloc(count, GFP_KERNEL);
if (!interval_string)
return -ENOMEM;
not_copied = copy_from_user(interval_string, buffer, count);
interval_string[count - not_copied - 1] = 0;
retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
if (retval) {
debug_log(LOG_TYPE_WARN, "New originator interval invalid\n");
goto end;
}
if (originator_interval_tmp <= JITTER * 2) {
debug_log(LOG_TYPE_WARN,
"New originator interval too small: %i (min: %i)\n",
originator_interval_tmp, JITTER * 2);
goto end;
}
debug_log(LOG_TYPE_NOTICE,
"Changing originator interval from: %i to: %i\n",
atomic_read(&originator_interval), originator_interval_tmp);
atomic_set(&originator_interval, originator_interval_tmp);
end:
kfree(interval_string);
return count;
}
static int proc_orig_interval_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_orig_interval_read, NULL);
}
static int proc_originators_read(struct seq_file *seq, void *offset)
{
struct hash_it_t *hashit = NULL;
struct orig_node *orig_node;
struct neigh_node *neigh_node;
int batman_count = 0;
char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
rcu_read_lock();
if (list_empty(&if_list)) {
rcu_read_unlock();
seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
goto end;
}
if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
rcu_read_unlock();
seq_printf(seq, "BATMAN disabled - primary interface not active \n");
goto end;
}
seq_printf(seq,
" %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
"Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
"Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
((struct batman_if *)if_list.next)->dev,
((struct batman_if *)if_list.next)->addr_str);
rcu_read_unlock();
spin_lock(&orig_hash_lock);
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
if (!orig_node->router)
continue;
if (orig_node->router->tq_avg == 0)
continue;
batman_count++;
addr_to_string(orig_str, orig_node->orig);
addr_to_string(router_str, orig_node->router->addr);
seq_printf(seq, "%-17s (%3i) %17s [%10s]:",
orig_str, orig_node->router->tq_avg,
router_str, orig_node->router->if_incoming->dev);
list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
addr_to_string(orig_str, neigh_node->addr);
seq_printf(seq, " %17s (%3i)",
orig_str, neigh_node->tq_avg);
}
seq_printf(seq, "\n");
}
spin_unlock(&orig_hash_lock);
if (batman_count == 0)
seq_printf(seq, "No batman nodes in range ... \n");
end:
return 0;
}
static int proc_originators_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_originators_read, NULL);
}
static int proc_log_level_read(struct seq_file *seq, void *offset)
{
seq_printf(seq, "[x] %s (%d)\n", LOG_TYPE_CRIT_NAME, LOG_TYPE_CRIT);
seq_printf(seq, "[%c] %s (%d)\n",
(LOG_TYPE_WARN & log_level) ? 'x' : ' ',
LOG_TYPE_WARN_NAME, LOG_TYPE_WARN);
seq_printf(seq, "[%c] %s (%d)\n",
(LOG_TYPE_NOTICE & log_level) ? 'x' : ' ',
LOG_TYPE_NOTICE_NAME, LOG_TYPE_NOTICE);
seq_printf(seq, "[%c] %s (%d)\n",
(LOG_TYPE_BATMAN & log_level) ? 'x' : ' ',
LOG_TYPE_BATMAN_NAME, LOG_TYPE_BATMAN);
seq_printf(seq, "[%c] %s (%d)\n",
(LOG_TYPE_ROUTES & log_level) ? 'x' : ' ',
LOG_TYPE_ROUTES_NAME, LOG_TYPE_ROUTES);
return 0;
}
static int proc_log_level_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_log_level_read, NULL);
}
static ssize_t proc_log_level_write(struct file *instance,
const char __user *userbuffer,
size_t count, loff_t *data)
{
char *log_level_string, *tokptr, *cp;
int finished, not_copied = 0;
unsigned long log_level_tmp = 0;
log_level_string = kmalloc(count, GFP_KERNEL);
if (!log_level_string)
return -ENOMEM;
not_copied = copy_from_user(log_level_string, userbuffer, count);
log_level_string[count - not_copied - 1] = 0;
if (strict_strtoul(log_level_string, 10, &log_level_tmp) < 0) {
/* was not a number, doing textual parsing */
log_level_tmp = 0;
tokptr = log_level_string;
for (cp = log_level_string, finished = 0; !finished; cp++) {
switch (*cp) {
case 0:
finished = 1;
case ' ':
case '\n':
case '\t':
*cp = 0;
/* compare */
if (strcmp(tokptr, LOG_TYPE_WARN_NAME) == 0)
log_level_tmp |= LOG_TYPE_WARN;
if (strcmp(tokptr, LOG_TYPE_NOTICE_NAME) == 0)
log_level_tmp |= LOG_TYPE_NOTICE;
if (strcmp(tokptr, LOG_TYPE_BATMAN_NAME) == 0)
log_level_tmp |= LOG_TYPE_BATMAN;
if (strcmp(tokptr, LOG_TYPE_ROUTES_NAME) == 0)
log_level_tmp |= LOG_TYPE_ROUTES;
tokptr = cp + 1;
break;
default:
;
}
}
}
debug_log(LOG_TYPE_CRIT, "Changing log_level from: %i to: %i\n",
log_level, log_level_tmp);
log_level = log_level_tmp;
kfree(log_level_string);
return count;
}
static int proc_transt_local_read(struct seq_file *seq, void *offset)
{
char *buf;
buf = kmalloc(4096, GFP_KERNEL);
if (!buf)
return 0;
rcu_read_lock();
if (list_empty(&if_list)) {
rcu_read_unlock();
seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
goto end;
}
rcu_read_unlock();
seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name);
hna_local_fill_buffer_text(buf, 4096);
seq_printf(seq, "%s", buf);
end:
kfree(buf);
return 0;
}
static int proc_transt_local_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_transt_local_read, NULL);
}
static int proc_transt_global_read(struct seq_file *seq, void *offset)
{
char *buf;
buf = kmalloc(4096, GFP_KERNEL);
if (!buf)
return 0;
rcu_read_lock();
if (list_empty(&if_list)) {
rcu_read_unlock();
seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
goto end;
}
rcu_read_unlock();
seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n");
hna_global_fill_buffer_text(buf, 4096);
seq_printf(seq, "%s", buf);
end:
kfree(buf);
return 0;
}
static int proc_transt_global_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_transt_global_read, NULL);
}
/* insert interface to the list of interfaces of one originator */
static void proc_vis_insert_interface(const uint8_t *interface,
struct vis_if_list **if_entry,
bool primary)
{
/* Did we get an empty list? (then insert imediately) */
if(*if_entry == NULL) {
*if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
if (*if_entry == NULL)
return;
(*if_entry)->primary = primary;
(*if_entry)->next = NULL;
memcpy((*if_entry)->addr, interface, ETH_ALEN);
} else {
struct vis_if_list *head_if_entry = *if_entry;
/* Do we already have this interface in our list? */
while (!compare_orig((*if_entry)->addr, (void *)interface)) {
/* Or did we reach the end (then append the interface) */
if ((*if_entry)->next == NULL) {
(*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
if ((*if_entry)->next == NULL)
return;
memcpy((*if_entry)->next->addr, interface, ETH_ALEN);
(*if_entry)->next->primary = primary;
(*if_entry)->next->next = NULL;
break;
}
*if_entry = (*if_entry)->next;
}
/* Rewind the list to its head */
*if_entry = head_if_entry;
}
}
/* read an entry */
static void proc_vis_read_entry(struct seq_file *seq,
struct vis_info_entry *entry,
struct vis_if_list **if_entry,
uint8_t *vis_orig,
uint8_t current_format,
uint8_t first_line)
{
char from[40];
char to[40];
int int_part, frac_part;
addr_to_string(to, entry->dest);
if (entry->quality == 0) {
#ifndef VIS_SUBCLUSTERS_DISABLED
proc_vis_insert_interface(vis_orig, if_entry, true);
#endif /* VIS_SUBCLUSTERS_DISABLED */
addr_to_string(from, vis_orig);
if (current_format == DOT_DRAW) {
seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n",
from, to);
} else {
seq_printf(seq,
"%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }",
(first_line ? "" : ",\n"), from, to);
}
} else {
#ifndef VIS_SUBCLUSTERS_DISABLED
proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig));
#endif /* VIS_SUBCLUSTERS_DISABLED */
addr_to_string(from, entry->src);
/* kernel has no printf-support for %f? it'd be better to return
* this in float. */
int_part = TQ_MAX_VALUE / entry->quality;
frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000;
if (current_format == DOT_DRAW) {
seq_printf(seq,
"\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
from, to, int_part, frac_part);
} else {
seq_printf(seq,
"%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }",
(first_line ? "" : ",\n"), from, to, int_part, frac_part);
}
}
}
static int proc_vis_read(struct seq_file *seq, void *offset)
{
struct hash_it_t *hashit = NULL;
struct vis_info *info;
struct vis_info_entry *entries;
struct vis_if_list *if_entries = NULL;
int i;
uint8_t current_format, first_line = 1;
#ifndef VIS_SUBCLUSTERS_DISABLED
char tmp_addr_str[ETH_STR_LEN];
struct vis_if_list *tmp_if_next;
#endif /* VIS_SUBCLUSTERS_DISABLED */
current_format = vis_format;
rcu_read_lock();
if (list_empty(&if_list) || (!is_vis_server())) {
rcu_read_unlock();
if (current_format == DOT_DRAW)
seq_printf(seq, "digraph {\n}\n");
goto end;
}
rcu_read_unlock();
if (current_format == DOT_DRAW)
seq_printf(seq, "digraph {\n");
spin_lock(&vis_hash_lock);
while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
info = hashit->bucket->data;
entries = (struct vis_info_entry *)
((char *)info + sizeof(struct vis_info));
for (i = 0; i < info->packet.entries; i++) {
proc_vis_read_entry(seq, &entries[i], &if_entries,
info->packet.vis_orig,
current_format, first_line);
if (first_line)
first_line = 0;
}
#ifndef VIS_SUBCLUSTERS_DISABLED
/* Generate subgraphs from the collected items */
if (current_format == DOT_DRAW) {
addr_to_string(tmp_addr_str, info->packet.vis_orig);
seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str);
while (if_entries != NULL) {
addr_to_string(tmp_addr_str, if_entries->addr);
if (if_entries->primary)
seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str);
else
seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str);
/* ... and empty the list while doing this */
tmp_if_next = if_entries->next;
kfree(if_entries);
if_entries = tmp_if_next;
}
seq_printf(seq, "\t}\n");
}
#endif /* VIS_SUBCLUSTERS_DISABLED */
}
spin_unlock(&vis_hash_lock);
if (current_format == DOT_DRAW)
seq_printf(seq, "}\n");
else
seq_printf(seq, "\n");
end:
return 0;
}
/* setting the mode of the vis server by the user */
static ssize_t proc_vis_write(struct file *file, const char __user * buffer,
size_t count, loff_t *ppos)
{
char *vis_mode_string;
int not_copied = 0;
vis_mode_string = kmalloc(count, GFP_KERNEL);
if (!vis_mode_string)
return -ENOMEM;
not_copied = copy_from_user(vis_mode_string, buffer, count);
vis_mode_string[count - not_copied - 1] = 0;
if (strcmp(vis_mode_string, "client") == 0) {
debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to client\n");
vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
} else if (strcmp(vis_mode_string, "server") == 0) {
debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to server\n");
vis_set_mode(VIS_TYPE_SERVER_SYNC);
} else
debug_log(LOG_TYPE_WARN, "Unknown VIS mode: %s\n",
vis_mode_string);
kfree(vis_mode_string);
return count;
}
static int proc_vis_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_vis_read, NULL);
}
static int proc_vis_format_read(struct seq_file *seq, void *offset)
{
uint8_t current_format = vis_format;
seq_printf(seq, "[%c] %s\n",
(current_format == DOT_DRAW) ? 'x' : ' ',
VIS_FORMAT_DD_NAME);
seq_printf(seq, "[%c] %s\n",
(current_format == JSON) ? 'x' : ' ',
VIS_FORMAT_JSON_NAME);
return 0;
}
static int proc_vis_format_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_vis_format_read, NULL);
}
static ssize_t proc_vis_format_write(struct file *file,
const char __user *buffer,
size_t count, loff_t *ppos)
{
char *vis_format_string;
int not_copied = 0;
vis_format_string = kmalloc(count, GFP_KERNEL);
if (!vis_format_string)
return -ENOMEM;
not_copied = copy_from_user(vis_format_string, buffer, count);
vis_format_string[count - not_copied - 1] = 0;
if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) {
debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
VIS_FORMAT_DD_NAME);
vis_format = DOT_DRAW;
} else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) {
debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
VIS_FORMAT_JSON_NAME);
vis_format = JSON;
} else
debug_log(LOG_TYPE_WARN, "Unknown VIS output format: %s\n",
vis_format_string);
kfree(vis_format_string);
return count;
}
static int proc_aggr_read(struct seq_file *seq, void *offset)
{
seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled));
return 0;
}
static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char *aggr_string;
int not_copied = 0;
unsigned long aggregation_enabled_tmp;
aggr_string = kmalloc(count, GFP_KERNEL);
if (!aggr_string)
return -ENOMEM;
not_copied = copy_from_user(aggr_string, buffer, count);
aggr_string[count - not_copied - 1] = 0;
strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
debug_log(LOG_TYPE_WARN, "Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
goto end;
}
debug_log(LOG_TYPE_NOTICE, "Changing aggregation from: %s (%i) to: %s (%li)\n",
(atomic_read(&aggregation_enabled) == 1 ?
"enabled" : "disabled"),
atomic_read(&aggregation_enabled),
(aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
aggregation_enabled_tmp);
atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
end:
kfree(aggr_string);
return count;
}
static int proc_aggr_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_aggr_read, NULL);
}
/* satisfying different prototypes ... */
static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
return count;
}
static const struct file_operations proc_aggr_fops = {
.owner = THIS_MODULE,
.open = proc_aggr_open,
.read = seq_read,
.write = proc_aggr_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_vis_format_fops = {
.owner = THIS_MODULE,
.open = proc_vis_format_open,
.read = seq_read,
.write = proc_vis_format_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_vis_fops = {
.owner = THIS_MODULE,
.open = proc_vis_open,
.read = seq_read,
.write = proc_vis_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_originators_fops = {
.owner = THIS_MODULE,
.open = proc_originators_open,
.read = seq_read,
.write = proc_dummy_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_transt_local_fops = {
.owner = THIS_MODULE,
.open = proc_transt_local_open,
.read = seq_read,
.write = proc_dummy_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_transt_global_fops = {
.owner = THIS_MODULE,
.open = proc_transt_global_open,
.read = seq_read,
.write = proc_dummy_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_log_level_fops = {
.owner = THIS_MODULE,
.open = proc_log_level_open,
.read = seq_read,
.write = proc_log_level_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_interfaces_fops = {
.owner = THIS_MODULE,
.open = proc_interfaces_open,
.read = seq_read,
.write = proc_interfaces_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations proc_orig_interval_fops = {
.owner = THIS_MODULE,
.open = proc_orig_interval_open,
.read = seq_read,
.write = proc_orig_interval_write,
.llseek = seq_lseek,
.release = single_release,
};
void cleanup_procfs(void)
{
if (proc_transt_global_file)
remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir);
if (proc_transt_local_file)
remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
if (proc_log_file)
remove_proc_entry(PROC_FILE_LOG, proc_batman_dir);
if (proc_log_level_file)
remove_proc_entry(PROC_FILE_LOG_LEVEL, proc_batman_dir);
if (proc_originators_file)
remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
if (proc_orig_interval_file)
remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
if (proc_interface_file)
remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
if (proc_vis_file)
remove_proc_entry(PROC_FILE_VIS, proc_batman_dir);
if (proc_vis_format_file)
remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir);
if (proc_aggr_file)
remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
if (proc_batman_dir)
#ifdef __NET_NET_NAMESPACE_H
remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
#else
remove_proc_entry(PROC_ROOT_DIR, proc_net);
#endif
}
int setup_procfs(void)
{
#ifdef __NET_NET_NAMESPACE_H
proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
#else
proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
#endif
if (!proc_batman_dir) {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
return -EFAULT;
}
proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_interface_file) {
proc_interface_file->proc_fops = &proc_interfaces_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
cleanup_procfs();
return -EFAULT;
}
proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_orig_interval_file) {
proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
cleanup_procfs();
return -EFAULT;
}
proc_log_level_file = create_proc_entry(PROC_FILE_LOG_LEVEL,
S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_log_level_file) {
proc_log_level_file->proc_fops = &proc_log_level_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_LOG_LEVEL);
cleanup_procfs();
return -EFAULT;
}
proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
S_IRUGO, proc_batman_dir);
if (proc_originators_file) {
proc_originators_file->proc_fops = &proc_originators_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS);
cleanup_procfs();
return -EFAULT;
}
proc_log_file = create_proc_entry(PROC_FILE_LOG,
S_IRUGO, proc_batman_dir);
if (proc_log_file) {
proc_log_file->proc_fops = &proc_log_operations;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_FILE_LOG, PROC_FILE_GATEWAYS);
cleanup_procfs();
return -EFAULT;
}
proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
S_IRUGO, proc_batman_dir);
if (proc_transt_local_file) {
proc_transt_local_file->proc_fops = &proc_transt_local_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL);
cleanup_procfs();
return -EFAULT;
}
proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL,
S_IRUGO, proc_batman_dir);
if (proc_transt_global_file) {
proc_transt_global_file->proc_fops = &proc_transt_global_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL);
cleanup_procfs();
return -EFAULT;
}
proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_vis_file) {
proc_vis_file->proc_fops = &proc_vis_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS);
cleanup_procfs();
return -EFAULT;
}
proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT,
S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_vis_format_file) {
proc_vis_format_file->proc_fops = &proc_vis_format_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT);
cleanup_procfs();
return -EFAULT;
}
proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_aggr_file) {
proc_aggr_file->proc_fops = &proc_aggr_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR);
cleanup_procfs();
return -EFAULT;
}
return 0;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#define PROC_ROOT_DIR "batman-adv"
#define PROC_FILE_INTERFACES "interfaces"
#define PROC_FILE_ORIG_INTERVAL "orig_interval"
#define PROC_FILE_ORIGINATORS "originators"
#define PROC_FILE_GATEWAYS "gateways"
#define PROC_FILE_LOG "log"
#define PROC_FILE_LOG_LEVEL "log_level"
#define PROC_FILE_TRANST_LOCAL "transtable_local"
#define PROC_FILE_TRANST_GLOBAL "transtable_global"
#define PROC_FILE_VIS "vis"
#define PROC_FILE_VIS_FORMAT "vis_format"
#define PROC_FILE_AGGR "aggregate_ogm"
void cleanup_procfs(void);
int setup_procfs(void);
/* While scanning for vis-entries of a particular vis-originator
* this list collects its interfaces to create a subgraph/cluster
* out of them later
*/
struct vis_if_list {
uint8_t addr[ETH_ALEN];
bool primary;
struct vis_if_list *next;
};

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "ring_buffer.h"
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
{
lq_recv[*lq_index] = value;
*lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
}
uint8_t ring_buffer_avg(uint8_t lq_recv[])
{
uint8_t *ptr;
uint16_t count = 0, i = 0, sum = 0;
ptr = lq_recv;
while (i < TQ_GLOBAL_WINDOW_SIZE) {
if (*ptr != 0) {
count++;
sum += *ptr;
}
i++;
ptr++;
}
if (count == 0)
return 0;
return (uint8_t)(sum / count);
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
uint8_t ring_buffer_avg(uint8_t lq_recv[]);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
extern wait_queue_head_t thread_wait;
extern atomic_t exit_cond;
int originator_init(void);
void free_orig_node(void *data);
void originator_free(void);
void slide_own_bcast_window(struct batman_if *batman_if);
void batman_data_ready(struct sock *sk, int len);
void purge_orig(struct work_struct *work);
int packet_recv_thread(void *data);
void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming);

View File

@ -0,0 +1,473 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "send.h"
#include "log.h"
#include "routing.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "vis.h"
#include "aggregation.h"
#include "compat.h"
/* apply hop penalty for a normal link */
static uint8_t hop_penalty(const uint8_t tq)
{
return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE);
}
/* when do we schedule our own packet to be sent */
static unsigned long own_send_time(void)
{
return jiffies +
(((atomic_read(&originator_interval) - JITTER +
(random32() % 2*JITTER)) * HZ) / 1000);
}
/* when do we schedule a forwarded packet to be sent */
static unsigned long forward_send_time(void)
{
unsigned long send_time = jiffies; /* Starting now plus... */
if (atomic_read(&aggregation_enabled))
send_time += (((MAX_AGGREGATION_MS - (JITTER/2) +
(random32() % JITTER)) * HZ) / 1000);
else
send_time += (((random32() % (JITTER/2)) * HZ) / 1000);
return send_time;
}
/* sends a raw packet. */
void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
struct batman_if *batman_if, uint8_t *dst_addr)
{
struct ethhdr *ethhdr;
struct sk_buff *skb;
int retval;
char *data;
if (batman_if->if_active != IF_ACTIVE)
return;
if (!(batman_if->net_dev->flags & IFF_UP)) {
debug_log(LOG_TYPE_WARN,
"Interface %s is not up - can't send packet via that interface (IF_TO_BE_DEACTIVATED was here) !\n",
batman_if->dev);
return;
}
skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr));
if (!skb)
return;
data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr));
memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len);
ethhdr = (struct ethhdr *) data;
memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
skb_reset_mac_header(skb);
skb_set_network_header(skb, ETH_HLEN);
skb->priority = TC_PRIO_CONTROL;
skb->protocol = __constant_htons(ETH_P_BATMAN);
skb->dev = batman_if->net_dev;
/* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP
* (which is > 0). This will not be treated as an error. */
retval = dev_queue_xmit(skb);
if (retval < 0)
debug_log(LOG_TYPE_CRIT,
"Can't write to raw socket (IF_TO_BE_DEACTIVATED was here): %i\n",
retval);
}
/* Send a packet to a given interface */
static void send_packet_to_if(struct forw_packet *forw_packet,
struct batman_if *batman_if)
{
char *fwd_str;
uint8_t packet_num;
int16_t buff_pos;
struct batman_packet *batman_packet;
char orig_str[ETH_STR_LEN];
if (batman_if->if_active != IF_ACTIVE)
return;
packet_num = buff_pos = 0;
batman_packet = (struct batman_packet *)
(forw_packet->packet_buff);
/* adjust all flags and log packets */
while (aggregated_packet(buff_pos,
forw_packet->packet_len,
batman_packet->num_hna)) {
/* we might have aggregated direct link packets with an
* ordinary base packet */
if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
(forw_packet->if_incoming == batman_if))
batman_packet->flags |= DIRECTLINK;
else
batman_packet->flags &= ~DIRECTLINK;
addr_to_string(orig_str, batman_packet->orig);
fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
"Sending own" :
"Forwarding"));
debug_log(LOG_TYPE_BATMAN,
"%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n",
fwd_str,
(packet_num > 0 ? "aggregated " : ""),
orig_str, ntohs(batman_packet->seqno),
batman_packet->tq, batman_packet->ttl,
(batman_packet->flags & DIRECTLINK ?
"on" : "off"),
batman_if->dev, batman_if->addr_str);
buff_pos += sizeof(struct batman_packet) +
(batman_packet->num_hna * ETH_ALEN);
packet_num++;
batman_packet = (struct batman_packet *)
(forw_packet->packet_buff + buff_pos);
}
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
batman_if, broadcastAddr);
}
/* send a batman packet */
static void send_packet(struct forw_packet *forw_packet)
{
struct batman_if *batman_if;
struct batman_packet *batman_packet =
(struct batman_packet *)(forw_packet->packet_buff);
char orig_str[ETH_STR_LEN];
unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
debug_log(LOG_TYPE_CRIT,
"Error - can't forward packet: incoming iface not specified\n");
return;
}
if (forw_packet->if_incoming->if_active != IF_ACTIVE)
return;
addr_to_string(orig_str, batman_packet->orig);
/* multihomed peer assumed */
/* non-primary OGMs are only broadcasted on their interface */
if ((directlink && (batman_packet->ttl == 1)) ||
(forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */
debug_log(LOG_TYPE_BATMAN,
"%s packet (originator %s, seqno %d, TTL %d) on interface %s [%s]\n",
(forw_packet->own ? "Sending own" : "Forwarding"),
orig_str, ntohs(batman_packet->seqno),
batman_packet->ttl, forw_packet->if_incoming->dev,
forw_packet->if_incoming->addr_str);
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
forw_packet->if_incoming,
broadcastAddr);
return;
}
/* broadcast on every interface */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list)
send_packet_to_if(forw_packet, batman_if);
rcu_read_unlock();
}
static void rebuild_batman_packet(struct batman_if *batman_if)
{
int new_len;
unsigned char *new_buff;
struct batman_packet *batman_packet;
new_len = sizeof(struct batman_packet) + (num_hna * ETH_ALEN);
new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, batman_if->packet_buff,
sizeof(struct batman_packet));
batman_packet = (struct batman_packet *)new_buff;
batman_packet->num_hna = hna_local_fill_buffer(
new_buff + sizeof(struct batman_packet),
new_len - sizeof(struct batman_packet));
kfree(batman_if->packet_buff);
batman_if->packet_buff = new_buff;
batman_if->packet_len = new_len;
}
}
void schedule_own_packet(struct batman_if *batman_if)
{
unsigned long send_time;
struct batman_packet *batman_packet;
/**
* the interface gets activated here to avoid race conditions between
* the moment of activating the interface in
* hardif_activate_interface() where the originator mac is set and
* outdated packets (especially uninitialized mac addresses) in the
* packet queue
*/
if (batman_if->if_active == IF_TO_BE_ACTIVATED)
batman_if->if_active = IF_ACTIVE;
/* if local hna has changed and interface is a primary interface */
if ((atomic_read(&hna_local_changed)) && (batman_if->if_num == 0))
rebuild_batman_packet(batman_if);
/**
* NOTE: packet_buff might just have been re-allocated in
* rebuild_batman_packet()
*/
batman_packet = (struct batman_packet *)batman_if->packet_buff;
/* change sequence number to network order */
batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno));
if (is_vis_server())
batman_packet->flags = VIS_SERVER;
else
batman_packet->flags = 0;
/* could be read by receive_bat_packet() */
atomic_inc(&batman_if->seqno);
slide_own_bcast_window(batman_if);
send_time = own_send_time();
add_bat_packet_to_list(batman_if->packet_buff,
batman_if->packet_len, batman_if, 1, send_time);
}
void schedule_forward_packet(struct orig_node *orig_node,
struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
uint8_t directlink, int hna_buff_len,
struct batman_if *if_incoming)
{
unsigned char in_tq, in_ttl, tq_avg = 0;
unsigned long send_time;
if (batman_packet->ttl <= 1) {
debug_log(LOG_TYPE_BATMAN, "ttl exceeded \n");
return;
}
in_tq = batman_packet->tq;
in_ttl = batman_packet->ttl;
batman_packet->ttl--;
memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
* of our best tq value */
if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
/* rebroadcast ogm of best ranking neighbor as is */
if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) {
batman_packet->tq = orig_node->router->tq_avg;
if (orig_node->router->last_ttl)
batman_packet->ttl = orig_node->router->last_ttl - 1;
}
tq_avg = orig_node->router->tq_avg;
}
/* apply hop penalty */
batman_packet->tq = hop_penalty(batman_packet->tq);
debug_log(LOG_TYPE_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n",
in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
batman_packet->ttl);
batman_packet->seqno = htons(batman_packet->seqno);
if (directlink)
batman_packet->flags |= DIRECTLINK;
else
batman_packet->flags &= ~DIRECTLINK;
send_time = forward_send_time();
add_bat_packet_to_list((unsigned char *)batman_packet,
sizeof(struct batman_packet) + hna_buff_len,
if_incoming, 0, send_time);
}
static void forw_packet_free(struct forw_packet *forw_packet)
{
kfree(forw_packet->packet_buff);
kfree(forw_packet);
}
static void _add_bcast_packet_to_list(struct forw_packet *forw_packet,
unsigned long send_time)
{
INIT_HLIST_NODE(&forw_packet->list);
/* add new packet to packet list */
spin_lock(&forw_bcast_list_lock);
hlist_add_head(&forw_packet->list, &forw_bcast_list);
spin_unlock(&forw_bcast_list_lock);
/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet->delayed_work,
send_outstanding_bcast_packet);
queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
send_time);
}
void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
{
struct forw_packet *forw_packet;
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
if (!forw_packet)
return;
forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC);
if (!forw_packet->packet_buff)
return;
forw_packet->packet_len = packet_len;
memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len);
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
_add_bcast_packet_to_list(forw_packet, 1);
}
void send_outstanding_bcast_packet(struct work_struct *work)
{
struct batman_if *batman_if;
struct delayed_work *delayed_work =
container_of(work, struct delayed_work, work);
struct forw_packet *forw_packet =
container_of(delayed_work, struct forw_packet, delayed_work);
spin_lock(&forw_bcast_list_lock);
hlist_del(&forw_packet->list);
spin_unlock(&forw_bcast_list_lock);
/* rebroadcast packet */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
batman_if, broadcastAddr);
}
rcu_read_unlock();
forw_packet->num_packets++;
/* if we still have some more bcasts to send and we are not shutting
* down */
if ((forw_packet->num_packets < 3) &&
(atomic_read(&module_state) != MODULE_DEACTIVATING))
_add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000));
else
forw_packet_free(forw_packet);
}
void send_outstanding_bat_packet(struct work_struct *work)
{
struct delayed_work *delayed_work =
container_of(work, struct delayed_work, work);
struct forw_packet *forw_packet =
container_of(delayed_work, struct forw_packet, delayed_work);
spin_lock(&forw_bat_list_lock);
hlist_del(&forw_packet->list);
spin_unlock(&forw_bat_list_lock);
send_packet(forw_packet);
/**
* we have to have at least one packet in the queue
* to determine the queues wake up time unless we are
* shutting down
*/
if ((forw_packet->own) &&
(atomic_read(&module_state) != MODULE_DEACTIVATING))
schedule_own_packet(forw_packet->if_incoming);
forw_packet_free(forw_packet);
}
void purge_outstanding_packets(void)
{
struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node;
debug_log(LOG_TYPE_BATMAN, "purge_outstanding_packets()\n");
/* free bcast list */
spin_lock(&forw_bcast_list_lock);
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bcast_list, list) {
spin_unlock(&forw_bcast_list_lock);
/**
* send_outstanding_bcast_packet() will lock the list to
* delete the item from the list
*/
cancel_delayed_work_sync(&forw_packet->delayed_work);
spin_lock(&forw_bcast_list_lock);
}
spin_unlock(&forw_bcast_list_lock);
/* free batman packet list */
spin_lock(&forw_bat_list_lock);
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bat_list, list) {
spin_unlock(&forw_bat_list_lock);
/**
* send_outstanding_bat_packet() will lock the list to
* delete the item from the list
*/
cancel_delayed_work_sync(&forw_packet->delayed_work);
spin_lock(&forw_bat_list_lock);
}
spin_unlock(&forw_bat_list_lock);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
void send_own_packet_work(struct work_struct *work);
void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
struct batman_if *batman_if, uint8_t *dst_addr);
void schedule_own_packet(struct batman_if *batman_if);
void schedule_forward_packet(struct orig_node *orig_node,
struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
uint8_t directlink, int hna_buff_len,
struct batman_if *if_outgoing);
void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len);
void send_outstanding_bcast_packet(struct work_struct *work);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(void);

View File

@ -0,0 +1,349 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "send.h"
#include "translation-table.h"
#include "log.h"
#include "types.h"
#include "hash.h"
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include "compat.h"
static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
* broadcast storms */
static int32_t skb_packets;
static int32_t skb_bad_packets;
static int32_t lock_dropped;
unsigned char mainIfAddr[ETH_ALEN];
static unsigned char mainIfAddr_default[ETH_ALEN];
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static void bat_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info);
static u32 bat_get_msglevel(struct net_device *dev);
static void bat_set_msglevel(struct net_device *dev, u32 value);
static u32 bat_get_link(struct net_device *dev);
static u32 bat_get_rx_csum(struct net_device *dev);
static int bat_set_rx_csum(struct net_device *dev, u32 data);
static const struct ethtool_ops bat_ethtool_ops = {
.get_settings = bat_get_settings,
.get_drvinfo = bat_get_drvinfo,
.get_msglevel = bat_get_msglevel,
.set_msglevel = bat_set_msglevel,
.get_link = bat_get_link,
.get_rx_csum = bat_get_rx_csum,
.set_rx_csum = bat_set_rx_csum
};
void set_main_if_addr(uint8_t *addr)
{
memcpy(mainIfAddr, addr, ETH_ALEN);
}
int main_if_was_up(void)
{
return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
}
static int my_skb_push(struct sk_buff *skb, unsigned int len)
{
int result = 0;
skb_packets++;
if (skb->data - len < skb->head) {
skb_bad_packets++;
result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
if (result < 0)
return result;
}
skb_push(skb, len);
return 0;
}
#ifdef HAVE_NET_DEVICE_OPS
static const struct net_device_ops bat_netdev_ops = {
.ndo_open = interface_open,
.ndo_stop = interface_release,
.ndo_get_stats = interface_stats,
.ndo_set_mac_address = interface_set_mac_addr,
.ndo_change_mtu = interface_change_mtu,
.ndo_start_xmit = interface_tx,
.ndo_validate_addr = eth_validate_addr
};
#endif
void interface_setup(struct net_device *dev)
{
struct bat_priv *priv = netdev_priv(dev);
char dev_addr[ETH_ALEN];
ether_setup(dev);
#ifdef HAVE_NET_DEVICE_OPS
dev->netdev_ops = &bat_netdev_ops;
#else
dev->open = interface_open;
dev->stop = interface_release;
dev->get_stats = interface_stats;
dev->set_mac_address = interface_set_mac_addr;
dev->change_mtu = interface_change_mtu;
dev->hard_start_xmit = interface_tx;
#endif
dev->destructor = free_netdev;
dev->mtu = hardif_min_mtu();
dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
* skbuff for our header */
/* generate random address */
random_ether_addr(dev_addr);
memcpy(dev->dev_addr, dev_addr, sizeof(dev->dev_addr));
SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
memset(priv, 0, sizeof(struct bat_priv));
}
int interface_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
int interface_release(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
struct net_device_stats *interface_stats(struct net_device *dev)
{
struct bat_priv *priv = netdev_priv(dev);
return &priv->stats;
}
int interface_set_mac_addr(struct net_device *dev, void *addr)
{
return -EBUSY;
}
int interface_change_mtu(struct net_device *dev, int new_mtu)
{
/* check ranges */
if ((new_mtu < 68) || (new_mtu > hardif_min_mtu()))
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
int interface_tx(struct sk_buff *skb, struct net_device *dev)
{
struct unicast_packet *unicast_packet;
struct bcast_packet *bcast_packet;
struct orig_node *orig_node;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *priv = netdev_priv(dev);
int data_len = skb->len;
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto dropped;
dev->trans_start = jiffies;
/* TODO: check this for locks */
hna_local_add(ethhdr->h_source);
/* ethernet packet should be broadcasted */
if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0)
goto dropped;
bcast_packet = (struct bcast_packet *)skb->data;
bcast_packet->version = COMPAT_VERSION;
/* batman packet type: broadcast */
bcast_packet->packet_type = BAT_BCAST;
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
/* set broadcast sequence number */
bcast_packet->seqno = htons(bcast_seqno);
bcast_seqno++;
/* broadcast packet */
add_bcast_packet_to_list(skb->data, skb->len);
/* unicast packet */
} else {
/* simply spin_lock()ing can deadlock when the lock is already
* hold. */
/* TODO: defer the work in a working queue instead of
* dropping */
if (!spin_trylock(&orig_hash_lock)) {
lock_dropped++;
debug_log(LOG_TYPE_NOTICE, "%d packets dropped because lock was hold\n", lock_dropped);
goto dropped;
}
/* get routing information */
orig_node = ((struct orig_node *)hash_find(orig_hash,
ethhdr->h_dest));
/* check for hna host */
if (!orig_node)
orig_node = transtable_search(ethhdr->h_dest);
if ((orig_node) &&
(orig_node->batman_if) &&
(orig_node->router)) {
if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
goto unlock;
unicast_packet = (struct unicast_packet *)skb->data;
unicast_packet->version = COMPAT_VERSION;
/* batman packet type: unicast */
unicast_packet->packet_type = BAT_UNICAST;
/* set unicast ttl */
unicast_packet->ttl = TTL;
/* copy the destination for faster routing */
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
/* net_dev won't be available when not active */
if (orig_node->batman_if->if_active != IF_ACTIVE)
goto unlock;
send_raw_packet(skb->data, skb->len,
orig_node->batman_if,
orig_node->router->addr);
} else {
goto unlock;
}
spin_unlock(&orig_hash_lock);
}
priv->stats.tx_packets++;
priv->stats.tx_bytes += data_len;
goto end;
unlock:
spin_unlock(&orig_hash_lock);
dropped:
priv->stats.tx_dropped++;
end:
kfree_skb(skb);
return 0;
}
void interface_rx(struct net_device *dev, void *packet, int packet_len)
{
struct sk_buff *skb;
struct bat_priv *priv = netdev_priv(dev);
skb = dev_alloc_skb(packet_len);
if (!skb) {
priv->stats.rx_dropped++;
goto out;
}
memcpy(skb_put(skb, packet_len), packet, packet_len);
/* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
priv->stats.rx_packets++;
priv->stats.rx_bytes += packet_len;
dev->last_rx = jiffies;
netif_rx(skb);
out:
return;
}
/* ethtool */
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = 0;
cmd->advertising = 0;
cmd->speed = SPEED_10;
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_TP;
cmd->phy_address = 0;
cmd->transceiver = XCVR_INTERNAL;
cmd->autoneg = AUTONEG_DISABLE;
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
return 0;
}
static void bat_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, "B.A.T.M.A.N. advanced");
strcpy(info->version, SOURCE_VERSION);
strcpy(info->fw_version, "N/A");
strcpy(info->bus_info, "batman");
}
static u32 bat_get_msglevel(struct net_device *dev)
{
return -EOPNOTSUPP;
}
static void bat_set_msglevel(struct net_device *dev, u32 value)
{
return;
}
static u32 bat_get_link(struct net_device *dev)
{
return 1;
}
static u32 bat_get_rx_csum(struct net_device *dev)
{
return 0;
}
static int bat_set_rx_csum(struct net_device *dev, u32 data)
{
return -EOPNOTSUPP;
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
void set_main_if_addr(uint8_t *addr);
int main_if_was_up(void);
void interface_setup(struct net_device *dev);
int interface_open(struct net_device *dev);
int interface_release(struct net_device *dev);
struct net_device_stats *interface_stats(struct net_device *dev);
int interface_set_mac_addr(struct net_device *dev, void *addr);
int interface_change_mtu(struct net_device *dev, int new_mtu);
int interface_tx(struct sk_buff *skb, struct net_device *dev);
void interface_rx(struct net_device *dev, void *packet, int packet_len);
extern unsigned char mainIfAddr[];

View File

@ -0,0 +1,454 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "translation-table.h"
#include "log.h"
#include "soft-interface.h"
#include "types.h"
#include "hash.h"
#include "compat.h"
struct hashtable_t *hna_local_hash;
static struct hashtable_t *hna_global_hash;
atomic_t hna_local_changed;
DEFINE_SPINLOCK(hna_local_hash_lock);
static DEFINE_SPINLOCK(hna_global_hash_lock);
static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge);
static void hna_local_start_timer(void)
{
queue_delayed_work(bat_event_workqueue, &hna_local_purge_wq, 10 * HZ);
}
int hna_local_init(void)
{
if (hna_local_hash)
return 1;
hna_local_hash = hash_new(128, compare_orig, choose_orig);
if (!hna_local_hash)
return 0;
atomic_set(&hna_local_changed, 0);
hna_local_start_timer();
return 1;
}
void hna_local_add(uint8_t *addr)
{
struct hna_local_entry *hna_local_entry;
struct hna_global_entry *hna_global_entry;
struct hashtable_t *swaphash;
char hna_str[ETH_STR_LEN];
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
hna_local_entry =
((struct hna_local_entry *)hash_find(hna_local_hash, addr));
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
if (hna_local_entry != NULL) {
hna_local_entry->last_seen = jiffies;
return;
}
addr_to_string(hna_str, addr);
/* only announce as many hosts as possible in the batman-packet and
space in batman_packet->num_hna That also should give a limit to
MAC-flooding. */
if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
(num_hna + 1 > 255)) {
debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str);
return;
}
debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n",
hna_str);
hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
if (!hna_local_entry)
return;
memcpy(hna_local_entry->addr, addr, ETH_ALEN);
hna_local_entry->last_seen = jiffies;
/* the batman interface mac address should never be purged */
if (compare_orig(addr, soft_device->dev_addr))
hna_local_entry->never_purge = 1;
else
hna_local_entry->never_purge = 0;
spin_lock_irqsave(&hna_local_hash_lock, flags);
hash_add(hna_local_hash, hna_local_entry);
num_hna++;
atomic_set(&hna_local_changed, 1);
if (hna_local_hash->elements * 4 > hna_local_hash->size) {
swaphash = hash_resize(hna_local_hash,
hna_local_hash->size * 2);
if (swaphash == NULL)
debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n");
else
hna_local_hash = swaphash;
}
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
/* remove address from global hash if present */
spin_lock_irqsave(&hna_global_hash_lock, flags);
hna_global_entry =
((struct hna_global_entry *)hash_find(hna_global_hash, addr));
if (hna_global_entry != NULL)
_hna_global_del_orig(hna_global_entry, "local hna received");
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
}
int hna_local_fill_buffer(unsigned char *buff, int buff_len)
{
struct hna_local_entry *hna_local_entry;
struct hash_it_t *hashit = NULL;
int i = 0;
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
if (buff_len < (i + 1) * ETH_ALEN)
break;
hna_local_entry = hashit->bucket->data;
memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
i++;
}
/* if we did not get all new local hnas see you next time ;-) */
if (i == num_hna)
atomic_set(&hna_local_changed, 0);
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
return i;
}
int hna_local_fill_buffer_text(unsigned char *buff, int buff_len)
{
struct hna_local_entry *hna_local_entry;
struct hash_it_t *hashit = NULL;
int bytes_written = 0;
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
if (buff_len < bytes_written + ETH_STR_LEN + 4)
break;
hna_local_entry = hashit->bucket->data;
bytes_written += snprintf(buff + bytes_written, ETH_STR_LEN + 4,
" * %02x:%02x:%02x:%02x:%02x:%02x\n",
hna_local_entry->addr[0],
hna_local_entry->addr[1],
hna_local_entry->addr[2],
hna_local_entry->addr[3],
hna_local_entry->addr[4],
hna_local_entry->addr[5]);
}
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
return bytes_written;
}
static void _hna_local_del(void *data)
{
kfree(data);
num_hna--;
atomic_set(&hna_local_changed, 1);
}
static void hna_local_del(struct hna_local_entry *hna_local_entry,
char *message)
{
char hna_str[ETH_STR_LEN];
addr_to_string(hna_str, hna_local_entry->addr);
debug_log(LOG_TYPE_ROUTES, "Deleting local hna entry (%s): %s \n",
hna_str, message);
hash_remove(hna_local_hash, hna_local_entry->addr);
_hna_local_del(hna_local_entry);
}
void hna_local_purge(struct work_struct *work)
{
struct hna_local_entry *hna_local_entry;
struct hash_it_t *hashit = NULL;
unsigned long flags;
unsigned long timeout;
spin_lock_irqsave(&hna_local_hash_lock, flags);
while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
hna_local_entry = hashit->bucket->data;
timeout = hna_local_entry->last_seen +
((LOCAL_HNA_TIMEOUT / 1000) * HZ);
if ((!hna_local_entry->never_purge) &&
time_after(jiffies, timeout))
hna_local_del(hna_local_entry, "address timed out");
}
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
hna_local_start_timer();
}
void hna_local_free(void)
{
if (!hna_local_hash)
return;
cancel_delayed_work_sync(&hna_local_purge_wq);
hash_delete(hna_local_hash, _hna_local_del);
hna_local_hash = NULL;
}
int hna_global_init(void)
{
if (hna_global_hash)
return 1;
hna_global_hash = hash_new(128, compare_orig, choose_orig);
if (!hna_global_hash)
return 0;
return 1;
}
void hna_global_add_orig(struct orig_node *orig_node,
unsigned char *hna_buff, int hna_buff_len)
{
struct hna_global_entry *hna_global_entry;
struct hna_local_entry *hna_local_entry;
struct hashtable_t *swaphash;
char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
int hna_buff_count = 0;
unsigned long flags;
unsigned char *hna_ptr;
addr_to_string(orig_str, orig_node->orig);
while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
spin_lock_irqsave(&hna_global_hash_lock, flags);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
hna_global_entry = (struct hna_global_entry *)
hash_find(hna_global_hash, hna_ptr);
if (hna_global_entry == NULL) {
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
hna_global_entry =
kmalloc(sizeof(struct hna_global_entry),
GFP_ATOMIC);
if (!hna_global_entry)
break;
memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
addr_to_string(hna_str, hna_global_entry->addr);
debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str);
spin_lock_irqsave(&hna_global_hash_lock, flags);
hash_add(hna_global_hash, hna_global_entry);
}
hna_global_entry->orig_node = orig_node;
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
/* remove address from local hash if present */
spin_lock_irqsave(&hna_local_hash_lock, flags);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
hna_local_entry = (struct hna_local_entry *)
hash_find(hna_local_hash, hna_ptr);
if (hna_local_entry != NULL)
hna_local_del(hna_local_entry, "global hna received");
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
hna_buff_count++;
}
orig_node->hna_buff_len = hna_buff_len;
if (orig_node->hna_buff_len > 0) {
orig_node->hna_buff = kmalloc(orig_node->hna_buff_len,
GFP_ATOMIC);
memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len);
} else {
orig_node->hna_buff = NULL;
}
spin_lock_irqsave(&hna_global_hash_lock, flags);
if (hna_global_hash->elements * 4 > hna_global_hash->size) {
swaphash = hash_resize(hna_global_hash,
hna_global_hash->size * 2);
if (swaphash == NULL)
debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n");
else
hna_global_hash = swaphash;
}
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
}
int hna_global_fill_buffer_text(unsigned char *buff, int buff_len)
{
struct hna_global_entry *hna_global_entry;
struct hash_it_t *hashit = NULL;
int bytes_written = 0;
unsigned long flags;
spin_lock_irqsave(&hna_global_hash_lock, flags);
while (NULL != (hashit = hash_iterate(hna_global_hash, hashit))) {
if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 10)
break;
hna_global_entry = hashit->bucket->data;
bytes_written += snprintf(buff + bytes_written,
(2 * ETH_STR_LEN) + 10,
" * %02x:%02x:%02x:%02x:%02x:%02x via %02x:%02x:%02x:%02x:%02x:%02x \n",
hna_global_entry->addr[0],
hna_global_entry->addr[1],
hna_global_entry->addr[2],
hna_global_entry->addr[3],
hna_global_entry->addr[4],
hna_global_entry->addr[5],
hna_global_entry->orig_node->orig[0],
hna_global_entry->orig_node->orig[1],
hna_global_entry->orig_node->orig[2],
hna_global_entry->orig_node->orig[3],
hna_global_entry->orig_node->orig[4],
hna_global_entry->orig_node->orig[5]);
}
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
return bytes_written;
}
void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
char *message)
{
char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
addr_to_string(orig_str, hna_global_entry->orig_node->orig);
addr_to_string(hna_str, hna_global_entry->addr);
debug_log(LOG_TYPE_ROUTES, "Deleting global hna entry %s (via %s): %s \n", hna_str, orig_str, message);
hash_remove(hna_global_hash, hna_global_entry->addr);
kfree(hna_global_entry);
}
void hna_global_del_orig(struct orig_node *orig_node, char *message)
{
struct hna_global_entry *hna_global_entry;
int hna_buff_count = 0;
unsigned long flags;
unsigned char *hna_ptr;
if (orig_node->hna_buff_len == 0)
return;
spin_lock_irqsave(&hna_global_hash_lock, flags);
while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
hna_global_entry = (struct hna_global_entry *)
hash_find(hna_global_hash, hna_ptr);
if ((hna_global_entry != NULL) &&
(hna_global_entry->orig_node == orig_node))
_hna_global_del_orig(hna_global_entry, message);
hna_buff_count++;
}
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
orig_node->hna_buff_len = 0;
kfree(orig_node->hna_buff);
orig_node->hna_buff = NULL;
}
static void hna_global_del(void *data)
{
kfree(data);
}
void hna_global_free(void)
{
if (!hna_global_hash)
return;
hash_delete(hna_global_hash, hna_global_del);
hna_global_hash = NULL;
}
struct orig_node *transtable_search(uint8_t *addr)
{
struct hna_global_entry *hna_global_entry;
unsigned long flags;
spin_lock_irqsave(&hna_global_hash_lock, flags);
hna_global_entry = (struct hna_global_entry *)
hash_find(hna_global_hash, addr);
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
if (hna_global_entry == NULL)
return NULL;
return hna_global_entry->orig_node;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
int hna_local_init(void);
void hna_local_add(uint8_t *addr);
int hna_local_fill_buffer(unsigned char *buff, int buff_len);
int hna_local_fill_buffer_text(unsigned char *buff, int buff_len);
void hna_local_purge(struct work_struct *work);
void hna_local_free(void);
int hna_global_init(void);
void hna_global_add_orig(struct orig_node *orig_node, unsigned char *hna_buff,
int hna_buff_len);
int hna_global_fill_buffer_text(unsigned char *buff, int buff_len);
void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
char *orig_str);
void hna_global_del_orig(struct orig_node *orig_node, char *message);
void hna_global_free(void);
struct orig_node *transtable_search(uint8_t *addr);
extern spinlock_t hna_local_hash_lock;
extern struct hashtable_t *hna_local_hash;
extern atomic_t hna_local_changed;

View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#ifndef TYPES_H
#define TYPES_H
#include "packet.h"
#include "bitarray.h"
#define BAT_HEADER_LEN (sizeof(struct ethhdr) + ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? sizeof(struct unicast_packet) : sizeof(struct bcast_packet))))
struct batman_if {
struct list_head list;
int16_t if_num;
char *dev;
char if_active;
char addr_str[ETH_STR_LEN];
struct net_device *net_dev;
struct socket *raw_sock;
atomic_t seqno;
unsigned char *packet_buff;
int packet_len;
struct rcu_head rcu;
};
struct orig_node { /* structure for orig_list maintaining nodes of mesh */
uint8_t orig[ETH_ALEN];
struct neigh_node *router;
struct batman_if *batman_if;
TYPE_OF_WORD *bcast_own;
uint8_t *bcast_own_sum;
uint8_t tq_own;
int tq_asym_penalty;
unsigned long last_valid; /* when last packet from this node was received */
/* uint8_t gwflags; * flags related to gateway functions: gateway class */
uint8_t flags; /* for now only VIS_SERVER flag. */
unsigned char *hna_buff;
int16_t hna_buff_len;
uint16_t last_real_seqno; /* last and best known squence number */
uint8_t last_ttl; /* ttl of last received packet */
TYPE_OF_WORD bcast_bits[NUM_WORDS];
uint16_t last_bcast_seqno; /* last broadcast sequence number received by this host */
struct list_head neigh_list;
};
struct neigh_node {
struct list_head list;
uint8_t addr[ETH_ALEN];
uint8_t real_packet_count;
uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
uint8_t tq_index;
uint8_t tq_avg;
uint8_t last_ttl;
unsigned long last_valid; /* when last packet via this neighbour was received */
TYPE_OF_WORD real_bits[NUM_WORDS];
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
struct bat_priv {
struct net_device_stats stats;
};
struct device_client {
struct list_head queue_list;
unsigned int queue_len;
unsigned char index;
spinlock_t lock;
wait_queue_head_t queue_wait;
};
struct device_packet {
struct list_head list;
struct icmp_packet icmp_packet;
};
struct hna_local_entry {
uint8_t addr[ETH_ALEN];
unsigned long last_seen;
char never_purge;
};
struct hna_global_entry {
uint8_t addr[ETH_ALEN];
struct orig_node *orig_node;
};
struct forw_packet { /* structure for forw_list maintaining packets to be send/forwarded */
struct hlist_node list;
unsigned long send_time;
uint8_t own;
unsigned char *packet_buff;
uint16_t packet_len;
uint32_t direct_link_flags;
uint8_t num_packets;
struct delayed_work delayed_work;
struct batman_if *if_incoming;
};
#endif

View File

@ -0,0 +1,564 @@
/*
* Copyright (C) 2008-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "send.h"
#include "translation-table.h"
#include "vis.h"
#include "log.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "hash.h"
#include "compat.h"
struct hashtable_t *vis_hash;
DEFINE_SPINLOCK(vis_hash_lock);
static struct vis_info *my_vis_info;
static struct list_head send_list; /* always locked with vis_hash_lock */
static void start_vis_timer(void);
/* free the info */
static void free_info(void *data)
{
struct vis_info *info = data;
struct recvlist_node *entry, *tmp;
list_del_init(&info->send_list);
list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
list_del(&entry->list);
kfree(entry);
}
kfree(info);
}
/* set the mode of the visualization to client or server */
void vis_set_mode(int mode)
{
spin_lock(&vis_hash_lock);
if (my_vis_info != NULL)
my_vis_info->packet.vis_type = mode;
spin_unlock(&vis_hash_lock);
}
/* is_vis_server(), locked outside */
static int is_vis_server_locked(void)
{
if (my_vis_info != NULL)
if (my_vis_info->packet.vis_type == VIS_TYPE_SERVER_SYNC)
return 1;
return 0;
}
/* get the current set mode */
int is_vis_server(void)
{
int ret = 0;
spin_lock(&vis_hash_lock);
ret = is_vis_server_locked();
spin_unlock(&vis_hash_lock);
return ret;
}
/* Compare two vis packets, used by the hashing algorithm */
static int vis_info_cmp(void *data1, void *data2)
{
struct vis_info *d1, *d2;
d1 = data1;
d2 = data2;
return compare_orig(d1->packet.vis_orig, d2->packet.vis_orig);
}
/* hash function to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
static int vis_info_choose(void *data, int size)
{
struct vis_info *vis_info = data;
unsigned char *key;
uint32_t hash = 0;
size_t i;
key = vis_info->packet.vis_orig;
for (i = 0; i < ETH_ALEN; i++) {
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash % size;
}
/* tries to add one entry to the receive list. */
static void recv_list_add(struct list_head *recv_list, char *mac)
{
struct recvlist_node *entry;
entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
if (!entry)
return;
memcpy(entry->mac, mac, ETH_ALEN);
list_add_tail(&entry->list, recv_list);
}
/* returns 1 if this mac is in the recv_list */
static int recv_list_is_in(struct list_head *recv_list, char *mac)
{
struct recvlist_node *entry;
list_for_each_entry(entry, recv_list, list) {
if (memcmp(entry->mac, mac, ETH_ALEN) == 0)
return 1;
}
return 0;
}
/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
* broken.. ). vis hash must be locked outside. is_new is set when the packet
* is newer than old entries in the hash. */
static struct vis_info *add_packet(struct vis_packet *vis_packet,
int vis_info_len, int *is_new)
{
struct vis_info *info, *old_info;
struct vis_info search_elem;
*is_new = 0;
/* sanity check */
if (vis_hash == NULL)
return NULL;
/* see if the packet is already in vis_hash */
memcpy(search_elem.packet.vis_orig, vis_packet->vis_orig, ETH_ALEN);
old_info = hash_find(vis_hash, &search_elem);
if (old_info != NULL) {
if (vis_packet->seqno - old_info->packet.seqno <= 0) {
if (old_info->packet.seqno == vis_packet->seqno) {
recv_list_add(&old_info->recv_list,
vis_packet->sender_orig);
return old_info;
} else {
/* newer packet is already in hash. */
return NULL;
}
}
/* remove old entry */
hash_remove(vis_hash, old_info);
free_info(old_info);
}
info = kmalloc(sizeof(struct vis_info) + vis_info_len, GFP_ATOMIC);
if (info == NULL)
return NULL;
INIT_LIST_HEAD(&info->send_list);
INIT_LIST_HEAD(&info->recv_list);
info->first_seen = jiffies;
memcpy(&info->packet, vis_packet,
sizeof(struct vis_packet) + vis_info_len);
/* initialize and add new packet. */
*is_new = 1;
/* repair if entries is longer than packet. */
if (info->packet.entries * sizeof(struct vis_info_entry) > vis_info_len)
info->packet.entries = vis_info_len / sizeof(struct vis_info_entry);
recv_list_add(&info->recv_list, info->packet.sender_orig);
/* try to add it */
if (hash_add(vis_hash, info) < 0) {
/* did not work (for some reason) */
free_info(info);
info = NULL;
}
return info;
}
/* handle the server sync packet, forward if needed. */
void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len)
{
struct vis_info *info;
int is_new;
spin_lock(&vis_hash_lock);
info = add_packet(vis_packet, vis_info_len, &is_new);
if (info == NULL)
goto end;
/* only if we are server ourselves and packet is newer than the one in
* hash.*/
if (is_vis_server_locked() && is_new) {
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
if (list_empty(&info->send_list))
list_add_tail(&info->send_list, &send_list);
}
end:
spin_unlock(&vis_hash_lock);
}
/* handle an incoming client update packet and schedule forward if needed. */
void receive_client_update_packet(struct vis_packet *vis_packet,
int vis_info_len)
{
struct vis_info *info;
int is_new;
/* clients shall not broadcast. */
if (is_bcast(vis_packet->target_orig))
return;
spin_lock(&vis_hash_lock);
info = add_packet(vis_packet, vis_info_len, &is_new);
if (info == NULL)
goto end;
/* note that outdated packets will be dropped at this point. */
/* send only if we're the target server or ... */
if (is_vis_server_locked() &&
is_my_mac(info->packet.target_orig) &&
is_new) {
info->packet.vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
if (list_empty(&info->send_list))
list_add_tail(&info->send_list, &send_list);
/* ... we're not the recipient (and thus need to forward). */
} else if (!is_my_mac(info->packet.target_orig)) {
if (list_empty(&info->send_list))
list_add_tail(&info->send_list, &send_list);
}
end:
spin_unlock(&vis_hash_lock);
}
/* Walk the originators and find the VIS server with the best tq. Set the packet
* address to its address and return the best_tq.
*
* Must be called with the originator hash locked */
static int find_best_vis_server(struct vis_info *info)
{
struct hash_it_t *hashit = NULL;
struct orig_node *orig_node;
int best_tq = -1;
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
if ((orig_node != NULL) &&
(orig_node->router != NULL) &&
(orig_node->flags & VIS_SERVER) &&
(orig_node->router->tq_avg > best_tq)) {
best_tq = orig_node->router->tq_avg;
memcpy(info->packet.target_orig, orig_node->orig,
ETH_ALEN);
}
}
return best_tq;
}
/* Return true if the vis packet is full. */
static bool vis_packet_full(struct vis_info *info)
{
if (info->packet.entries + 1 >
(1000 - sizeof(struct vis_info)) / sizeof(struct vis_info_entry))
return true;
return false;
}
/* generates a packet of own vis data,
* returns 0 on success, -1 if no packet could be generated */
static int generate_vis_packet(void)
{
struct hash_it_t *hashit = NULL;
struct orig_node *orig_node;
struct vis_info *info = (struct vis_info *)my_vis_info;
struct vis_info_entry *entry, *entry_array;
struct hna_local_entry *hna_local_entry;
int best_tq = -1;
unsigned long flags;
info->first_seen = jiffies;
spin_lock(&orig_hash_lock);
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
info->packet.ttl = TTL;
info->packet.seqno++;
info->packet.entries = 0;
if (!is_vis_server_locked()) {
best_tq = find_best_vis_server(info);
if (best_tq < 0) {
spin_unlock(&orig_hash_lock);
return -1;
}
}
hashit = NULL;
entry_array = (struct vis_info_entry *)
((char *)info + sizeof(struct vis_info));
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
if (orig_node->router != NULL
&& compare_orig(orig_node->router->addr, orig_node->orig)
&& orig_node->batman_if
&& (orig_node->batman_if->if_active == IF_ACTIVE)
&& orig_node->router->tq_avg > 0) {
/* fill one entry into buffer. */
entry = &entry_array[info->packet.entries];
memcpy(entry->src, orig_node->batman_if->net_dev->dev_addr, ETH_ALEN);
memcpy(entry->dest, orig_node->orig, ETH_ALEN);
entry->quality = orig_node->router->tq_avg;
info->packet.entries++;
if (vis_packet_full(info)) {
spin_unlock(&orig_hash_lock);
return 0;
}
}
}
spin_unlock(&orig_hash_lock);
hashit = NULL;
spin_lock_irqsave(&hna_local_hash_lock, flags);
while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
hna_local_entry = hashit->bucket->data;
entry = &entry_array[info->packet.entries];
memset(entry->src, 0, ETH_ALEN);
memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
entry->quality = 0; /* 0 means HNA */
info->packet.entries++;
if (vis_packet_full(info)) {
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
return 0;
}
}
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
return 0;
}
static void purge_vis_packets(void)
{
struct hash_it_t *hashit = NULL;
struct vis_info *info;
while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
info = hashit->bucket->data;
if (info == my_vis_info) /* never purge own data. */
continue;
if (time_after(jiffies,
info->first_seen + (VIS_TIMEOUT/1000)*HZ)) {
hash_remove_bucket(vis_hash, hashit);
free_info(info);
}
}
}
static void broadcast_vis_packet(struct vis_info *info, int packet_length)
{
struct hash_it_t *hashit = NULL;
struct orig_node *orig_node;
spin_lock(&orig_hash_lock);
/* send to all routers in range. */
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
/* if it's a vis server and reachable, send it. */
if (orig_node &&
(orig_node->flags & VIS_SERVER) &&
orig_node->batman_if &&
orig_node->router) {
/* don't send it if we already received the packet from
* this node. */
if (recv_list_is_in(&info->recv_list, orig_node->orig))
continue;
memcpy(info->packet.target_orig,
orig_node->orig, ETH_ALEN);
send_raw_packet((unsigned char *) &info->packet,
packet_length,
orig_node->batman_if,
orig_node->router->addr);
}
}
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
spin_unlock(&orig_hash_lock);
}
static void unicast_vis_packet(struct vis_info *info, int packet_length)
{
struct orig_node *orig_node;
spin_lock(&orig_hash_lock);
orig_node = ((struct orig_node *)
hash_find(orig_hash, info->packet.target_orig));
if ((orig_node != NULL) &&
(orig_node->batman_if != NULL) &&
(orig_node->router != NULL)) {
send_raw_packet((unsigned char *) &info->packet, packet_length,
orig_node->batman_if,
orig_node->router->addr);
}
spin_unlock(&orig_hash_lock);
}
/* only send one vis packet. called from send_vis_packets() */
static void send_vis_packet(struct vis_info *info)
{
int packet_length;
if (info->packet.ttl < 2) {
debug_log(LOG_TYPE_NOTICE,
"Error - can't send vis packet: ttl exceeded\n");
return;
}
memcpy(info->packet.sender_orig, mainIfAddr, ETH_ALEN);
info->packet.ttl--;
packet_length = sizeof(struct vis_packet) +
info->packet.entries * sizeof(struct vis_info_entry);
if (is_bcast(info->packet.target_orig))
broadcast_vis_packet(info, packet_length);
else
unicast_vis_packet(info, packet_length);
info->packet.ttl++; /* restore TTL */
}
/* called from timer; send (and maybe generate) vis packet. */
static void send_vis_packets(struct work_struct *work)
{
struct vis_info *info, *temp;
spin_lock(&vis_hash_lock);
purge_vis_packets();
if (generate_vis_packet() == 0)
/* schedule if generation was successful */
list_add_tail(&my_vis_info->send_list, &send_list);
list_for_each_entry_safe(info, temp, &send_list, send_list) {
list_del_init(&info->send_list);
send_vis_packet(info);
}
spin_unlock(&vis_hash_lock);
start_vis_timer();
}
static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets);
/* init the vis server. this may only be called when if_list is already
* initialized (e.g. bat0 is initialized, interfaces have been added) */
int vis_init(void)
{
if (vis_hash)
return 1;
spin_lock(&vis_hash_lock);
vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
if (!vis_hash) {
debug_log(LOG_TYPE_CRIT, "Can't initialize vis_hash\n");
goto err;
}
my_vis_info = kmalloc(1000, GFP_ATOMIC);
if (!my_vis_info) {
debug_log(LOG_TYPE_CRIT, "Can't initialize vis packet\n");
goto err;
}
/* prefill the vis info */
my_vis_info->first_seen = jiffies - atomic_read(&vis_interval);
INIT_LIST_HEAD(&my_vis_info->recv_list);
INIT_LIST_HEAD(&my_vis_info->send_list);
my_vis_info->packet.version = COMPAT_VERSION;
my_vis_info->packet.packet_type = BAT_VIS;
my_vis_info->packet.vis_type = VIS_TYPE_CLIENT_UPDATE;
my_vis_info->packet.ttl = TTL;
my_vis_info->packet.seqno = 0;
my_vis_info->packet.entries = 0;
INIT_LIST_HEAD(&send_list);
memcpy(my_vis_info->packet.vis_orig, mainIfAddr, ETH_ALEN);
memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN);
if (hash_add(vis_hash, my_vis_info) < 0) {
debug_log(LOG_TYPE_CRIT,
"Can't add own vis packet into hash\n");
free_info(my_vis_info); /* not in hash, need to remove it
* manually. */
goto err;
}
spin_unlock(&vis_hash_lock);
start_vis_timer();
return 1;
err:
spin_unlock(&vis_hash_lock);
vis_quit();
return 0;
}
/* shutdown vis-server */
void vis_quit(void)
{
if (!vis_hash)
return;
cancel_delayed_work_sync(&vis_timer_wq);
spin_lock(&vis_hash_lock);
/* properly remove, kill timers ... */
hash_delete(vis_hash, free_info);
vis_hash = NULL;
my_vis_info = NULL;
spin_unlock(&vis_hash_lock);
}
/* schedule packets for (re)transmission */
static void start_vis_timer(void)
{
queue_delayed_work(bat_event_workqueue, &vis_timer_wq,
(atomic_read(&vis_interval)/1000) * HZ);
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2008-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#define VIS_TIMEOUT 200000
#define VIS_FORMAT_DD_NAME "dot_draw"
#define VIS_FORMAT_JSON_NAME "json"
struct vis_info {
unsigned long first_seen;
struct list_head recv_list;
/* list of server-neighbors we received a vis-packet
* from. we should not reply to them. */
struct list_head send_list;
/* this packet might be part of the vis send queue. */
struct vis_packet packet;
/* vis_info may follow here*/
} __attribute__((packed));
struct vis_info_entry {
uint8_t src[ETH_ALEN];
uint8_t dest[ETH_ALEN];
uint8_t quality; /* quality = 0 means HNA */
} __attribute__((packed));
struct recvlist_node {
struct list_head list;
uint8_t mac[ETH_ALEN];
};
enum vis_formats {
DOT_DRAW,
JSON,
};
extern struct hashtable_t *vis_hash;
extern spinlock_t vis_hash_lock;
void vis_set_mode(int mode);
int is_vis_server(void);
void receive_server_sync_packet(struct vis_packet *vis_packet,
int vis_info_len);
void receive_client_update_packet(struct vis_packet *vis_packet,
int vis_info_len);
int vis_init(void);
void vis_quit(void);

View File

@ -24,10 +24,6 @@
#ifndef _COMEDI_H
#define _COMEDI_H
#ifdef __cplusplus
extern "C" {
#endif
#define COMEDI_MAJORVERSION 0
#define COMEDI_MINORVERSION 7
#define COMEDI_MICROVERSION 76
@ -871,8 +867,4 @@ INSN_CONFIG_ARM */
AMPLC_DIO_GAT_RESERVED7
};
#ifdef __cplusplus
}
#endif
#endif /* _COMEDI_H */

View File

@ -27,16 +27,12 @@
#define __NO_VERSION__
#include "comedi.h"
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include "comedi_compat32.h"
#ifdef CONFIG_COMPAT
#ifndef HAVE_COMPAT_IOCTL
#include <linux/ioctl32.h> /* for (un)register_ioctl32_conversion */
#endif
#define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
#define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
/* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
@ -101,22 +97,9 @@ static int translated_ioctl(struct file *file, unsigned int cmd,
if (!file->f_op)
return -ENOTTY;
#ifdef HAVE_UNLOCKED_IOCTL
if (file->f_op->unlocked_ioctl) {
int rc = (int)(*file->f_op->unlocked_ioctl) (file, cmd, arg);
if (rc == -ENOIOCTLCMD)
rc = -ENOTTY;
return rc;
}
#endif
if (file->f_op->ioctl) {
int rc;
lock_kernel();
rc = (*file->f_op->ioctl) (file->f_dentry->d_inode,
file, cmd, arg);
unlock_kernel();
return rc;
}
if (file->f_op->unlocked_ioctl)
return file->f_op->unlocked_ioctl(file, cmd, arg);
return -ENOTTY;
}
@ -186,8 +169,8 @@ static int compat_rangeinfo(struct file *file, unsigned long arg)
}
/* Copy 32-bit cmd structure to native cmd structure. */
static int get_compat_cmd(struct comedi_cmd __user * cmd,
struct comedi32_cmd_struct __user * cmd32)
static int get_compat_cmd(struct comedi_cmd __user *cmd,
struct comedi32_cmd_struct __user *cmd32)
{
int err;
union {
@ -237,8 +220,8 @@ static int get_compat_cmd(struct comedi_cmd __user * cmd,
}
/* Copy native cmd structure to 32-bit cmd structure. */
static int put_compat_cmd(struct comedi32_cmd_struct __user * cmd32,
struct comedi_cmd __user * cmd)
static int put_compat_cmd(struct comedi32_cmd_struct __user *cmd32,
struct comedi_cmd __user *cmd)
{
int err;
unsigned int temp;
@ -328,8 +311,8 @@ static int compat_cmdtest(struct file *file, unsigned long arg)
}
/* Copy 32-bit insn structure to native insn structure. */
static int get_compat_insn(struct comedi_insn __user * insn,
struct comedi32_insn_struct __user * insn32)
static int get_compat_insn(struct comedi_insn __user *insn,
struct comedi32_insn_struct __user *insn32)
{
int err;
union {
@ -372,9 +355,9 @@ static int compat_insnlist(struct file *file, unsigned long arg)
insnlist32 = compat_ptr(arg);
/* Get 32-bit insnlist structure. */
if (!access_ok(VERIFY_READ, insnlist32, sizeof(*insnlist32))) {
if (!access_ok(VERIFY_READ, insnlist32, sizeof(*insnlist32)))
return -EFAULT;
}
err = 0;
err |= __get_user(n_insns, &insnlist32->n_insns);
err |= __get_user(uptr, &insnlist32->insns);
@ -387,9 +370,9 @@ static int compat_insnlist(struct file *file, unsigned long arg)
insn[n_insns]));
/* Set native insnlist structure. */
if (!access_ok(VERIFY_WRITE, &s->insnlist, sizeof(s->insnlist))) {
if (!access_ok(VERIFY_WRITE, &s->insnlist, sizeof(s->insnlist)))
return -EFAULT;
}
err |= __put_user(n_insns, &s->insnlist.n_insns);
err |= __put_user(&s->insn[0], &s->insnlist.insns);
if (err)
@ -472,8 +455,6 @@ static inline int raw_ioctl(struct file *file, unsigned int cmd,
return rc;
}
#ifdef HAVE_COMPAT_IOCTL /* defined in <linux/fs.h> 2.6.11 onwards */
/* compat_ioctl file operation. */
/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@ -481,106 +462,4 @@ long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return raw_ioctl(file, cmd, arg);
}
#else /* HAVE_COMPAT_IOCTL */
/*
* Brain-dead ioctl compatibility for 2.6.10 and earlier.
*
* It's brain-dead because cmd numbers need to be unique system-wide!
* The comedi driver could end up attempting to execute ioctls for non-Comedi
* devices because it registered the system-wide cmd code first. Similarly,
* another driver could end up attempting to execute ioctls for a Comedi
* device because it registered the cmd code first. Chaos ensues.
*/
/* Handler for all 32-bit ioctl codes registered by this driver. */
static int mapped_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
struct file *file)
{
int rc;
/* Make sure we are dealing with a Comedi device. */
if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR)
return -ENOTTY;
rc = raw_ioctl(file, cmd, arg);
/* Do not return -ENOIOCTLCMD. */
if (rc == -ENOIOCTLCMD)
rc = -ENOTTY;
return rc;
}
struct ioctl32_map {
unsigned int cmd;
int (*handler) (unsigned int, unsigned int, unsigned long,
struct file *);
int registered;
};
static struct ioctl32_map comedi_ioctl32_map[] = {
{COMEDI_DEVCONFIG, mapped_ioctl, 0},
{COMEDI_DEVINFO, mapped_ioctl, 0},
{COMEDI_SUBDINFO, mapped_ioctl, 0},
{COMEDI_BUFCONFIG, mapped_ioctl, 0},
{COMEDI_BUFINFO, mapped_ioctl, 0},
{COMEDI_LOCK, mapped_ioctl, 0},
{COMEDI_UNLOCK, mapped_ioctl, 0},
{COMEDI_CANCEL, mapped_ioctl, 0},
{COMEDI_POLL, mapped_ioctl, 0},
{COMEDI32_CHANINFO, mapped_ioctl, 0},
{COMEDI32_RANGEINFO, mapped_ioctl, 0},
{COMEDI32_CMD, mapped_ioctl, 0},
{COMEDI32_CMDTEST, mapped_ioctl, 0},
{COMEDI32_INSNLIST, mapped_ioctl, 0},
{COMEDI32_INSN, mapped_ioctl, 0},
};
#define NUM_IOCTL32_MAPS ARRAY_SIZE(comedi_ioctl32_map)
/* Register system-wide 32-bit ioctl handlers. */
void comedi_register_ioctl32(void)
{
int n, rc;
for (n = 0; n < NUM_IOCTL32_MAPS; n++) {
rc = register_ioctl32_conversion(comedi_ioctl32_map[n].cmd,
comedi_ioctl32_map[n].handler);
if (rc) {
printk(KERN_WARNING
"comedi: failed to register 32-bit "
"compatible ioctl handler for 0x%X - "
"expect bad things to happen!\n",
comedi_ioctl32_map[n].cmd);
}
comedi_ioctl32_map[n].registered = !rc;
}
}
/* Unregister system-wide 32-bit ioctl translations. */
void comedi_unregister_ioctl32(void)
{
int n, rc;
for (n = 0; n < NUM_IOCTL32_MAPS; n++) {
if (comedi_ioctl32_map[n].registered) {
rc = unregister_ioctl32_conversion(comedi_ioctl32_map
[n].cmd,
comedi_ioctl32_map
[n].handler);
if (rc) {
printk(KERN_ERR
"comedi: failed to unregister 32-bit "
"compatible ioctl handler for 0x%X - "
"expect kernel Oops!\n",
comedi_ioctl32_map[n].cmd);
} else {
comedi_ioctl32_map[n].registered = 0;
}
}
}
}
#endif /* HAVE_COMPAT_IOCTL */
#endif /* CONFIG_COMPAT */

View File

@ -28,30 +28,16 @@
#define _COMEDI_COMPAT32_H
#include <linux/compat.h>
#include <linux/fs.h> /* For HAVE_COMPAT_IOCTL and HAVE_UNLOCKED_IOCTL */
#include <linux/fs.h>
#ifdef CONFIG_COMPAT
#ifdef HAVE_COMPAT_IOCTL
extern long comedi_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
#define comedi_register_ioctl32() do {} while (0)
#define comedi_unregister_ioctl32() do {} while (0)
#else /* HAVE_COMPAT_IOCTL */
#define comedi_compat_ioctl 0 /* NULL */
extern void comedi_register_ioctl32(void);
extern void comedi_unregister_ioctl32(void);
#endif /* HAVE_COMPAT_IOCTL */
#else /* CONFIG_COMPAT */
#define comedi_compat_ioctl 0 /* NULL */
#define comedi_register_ioctl32() do {} while (0)
#define comedi_unregister_ioctl32() do {} while (0)
#endif /* CONFIG_COMPAT */

View File

@ -110,13 +110,8 @@ static struct device_attribute dev_attr_read_buffer_kb;
static struct device_attribute dev_attr_max_write_buffer_kb;
static struct device_attribute dev_attr_write_buffer_kb;
#ifdef HAVE_UNLOCKED_IOCTL
static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
#else
static int comedi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
#endif
{
const unsigned minor = iminor(file->f_dentry->d_inode);
struct comedi_device_file_info *dev_file_info =
@ -1867,14 +1862,8 @@ static int comedi_fasync(int fd, struct file *file, int on)
const struct file_operations comedi_fops = {
.owner = THIS_MODULE,
#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = comedi_unlocked_ioctl,
#else
.ioctl = comedi_ioctl,
#endif
#ifdef HAVE_COMPAT_IOCTL
.compat_ioctl = comedi_compat_ioctl,
#endif
.open = comedi_open,
.release = comedi_close,
.read = comedi_read,
@ -1959,8 +1948,6 @@ static int __init comedi_init(void)
}
}
comedi_register_ioctl32();
return 0;
}
@ -1977,8 +1964,6 @@ static void __exit comedi_cleanup(void)
unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
comedi_proc_cleanup();
comedi_unregister_ioctl32();
}
module_init(comedi_init);

View File

@ -49,7 +49,8 @@
} while (0)
#define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, COMEDI_MINORVERSION, COMEDI_MICROVERSION)
#define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, \
COMEDI_MINORVERSION, COMEDI_MICROVERSION)
#define COMEDI_RELEASE VERSION
#define COMEDI_INITCLEANUP_NOMODULE(x) \
@ -58,12 +59,12 @@
static void __exit x ## _cleanup_module(void) \
{comedi_driver_unregister(&(x)); } \
module_init(x ## _init_module); \
module_exit(x ## _cleanup_module); \
module_exit(x ## _cleanup_module);
#define COMEDI_MODULE_MACROS \
MODULE_AUTHOR("Comedi http://www.comedi.org"); \
MODULE_DESCRIPTION("Comedi low-level driver"); \
MODULE_LICENSE("GPL"); \
MODULE_LICENSE("GPL");
#define COMEDI_INITCLEANUP(x) \
COMEDI_MODULE_MACROS \
@ -75,7 +76,8 @@
{ \
return comedi_pci_auto_config(dev, comedi_driver.driver_name); \
} \
static void __devexit comedi_driver ## _pci_remove(struct pci_dev *dev) \
static void __devexit comedi_driver ## _pci_remove(\
struct pci_dev *dev) \
{ \
comedi_pci_auto_unconfig(dev); \
} \
@ -91,7 +93,8 @@
retval = comedi_driver_register(&comedi_driver); \
if (retval < 0) \
return retval; \
comedi_driver ## _pci_driver.name = (char *)comedi_driver.driver_name; \
comedi_driver ## _pci_driver.name = \
(char *)comedi_driver.driver_name; \
return pci_register_driver(&comedi_driver ## _pci_driver); \
} \
static void __exit comedi_driver ## _cleanup_module(void) \
@ -170,14 +173,15 @@ struct comedi_subdevice {
struct comedi_cmd *);
int (*poll) (struct comedi_device *, struct comedi_subdevice *);
int (*cancel) (struct comedi_device *, struct comedi_subdevice *);
/* int (*do_lock)(struct comedi_device *,struct comedi_subdevice *); */
/* int (*do_unlock)(struct comedi_device *,struct comedi_subdevice *); */
/* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */
/* int (*do_unlock)(struct comedi_device *, \
struct comedi_subdevice *); */
/* called when the buffer changes */
int (*buf_change) (struct comedi_device * dev,
struct comedi_subdevice * s, unsigned long new_size);
int (*buf_change) (struct comedi_device *dev,
struct comedi_subdevice *s, unsigned long new_size);
void (*munge) (struct comedi_device * dev, struct comedi_subdevice * s,
void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s,
void *data, unsigned int num_bytes,
unsigned int start_chan_index);
enum dma_data_direction async_dma_dir;
@ -198,16 +202,22 @@ struct comedi_async {
void *prealloc_buf; /* pre-allocated buffer */
unsigned int prealloc_bufsz; /* buffer size, in bytes */
struct comedi_buf_page *buf_page_list; /* virtual and dma address of each page */
/* virtual and dma address of each page */
struct comedi_buf_page *buf_page_list;
unsigned n_buf_pages; /* num elements in buf_page_list */
unsigned int max_bufsize; /* maximum buffer size, bytes */
unsigned int mmap_count; /* current number of mmaps of prealloc_buf */
/* current number of mmaps of prealloc_buf */
unsigned int mmap_count;
unsigned int buf_write_count; /* byte count for writer (write completed) */
unsigned int buf_write_alloc_count; /* byte count for writer (allocated for writing) */
unsigned int buf_read_count; /* byte count for reader (read completed) */
unsigned int buf_read_alloc_count; /* byte count for reader (allocated for reading) */
/* byte count for writer (write completed) */
unsigned int buf_write_count;
/* byte count for writer (allocated for writing) */
unsigned int buf_write_alloc_count;
/* byte count for reader (read completed) */
unsigned int buf_read_count;
/* byte count for reader (allocated for reading) */
unsigned int buf_read_alloc_count;
unsigned int buf_write_ptr; /* buffer marker for writer */
unsigned int buf_read_ptr; /* buffer marker for reader */
@ -233,7 +243,7 @@ struct comedi_async {
int (*cb_func) (unsigned int flags, void *);
void *cb_arg;
int (*inttrig) (struct comedi_device * dev, struct comedi_subdevice * s,
int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int x);
};
@ -283,8 +293,8 @@ struct comedi_device {
struct fasync_struct *async_queue;
void (*open) (struct comedi_device * dev);
void (*close) (struct comedi_device * dev);
void (*open) (struct comedi_device *dev);
void (*close) (struct comedi_device *dev);
};
struct comedi_device_file_info {
@ -318,9 +328,8 @@ static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor);
static inline struct comedi_subdevice *comedi_get_read_subdevice(const struct
comedi_device_file_info
*info)
static inline struct comedi_subdevice *comedi_get_read_subdevice(
const struct comedi_device_file_info *info)
{
if (info->read_subdevice)
return info->read_subdevice;
@ -329,9 +338,8 @@ static inline struct comedi_subdevice *comedi_get_read_subdevice(const struct
return info->device->read_subdev;
}
static inline struct comedi_subdevice *comedi_get_write_subdevice(const struct
comedi_device_file_info
*info)
static inline struct comedi_subdevice *comedi_get_write_subdevice(
const struct comedi_device_file_info *info)
{
if (info->write_subdevice)
return info->write_subdevice;

View File

@ -387,7 +387,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
return 1;
}
static inline unsigned long uvirt_to_kva(pgd_t * pgd, unsigned long adr)
static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
unsigned long ret = 0UL;
pmd_t *pmd;

View File

@ -206,7 +206,8 @@ static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
}
*nanosec = div1 * div2 * i8253_osc_base;
*d1 = div1 & 0xffff; /* masking is done since counter maps zero to 0x10000 */
/* masking is done since counter maps zero to 0x10000 */
*d1 = div1 & 0xffff;
*d2 = div2 & 0xffff;
return;
}

View File

@ -132,6 +132,7 @@ void subdev_8255_interrupt(struct comedi_device *dev,
comedi_event(dev, s);
}
EXPORT_SYMBOL(subdev_8255_interrupt);
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
{
@ -179,15 +180,14 @@ static int subdev_8255_insn_config(struct comedi_device *dev,
unsigned int bits;
mask = 1 << CR_CHAN(insn->chanspec);
if (mask & 0x0000ff) {
if (mask & 0x0000ff)
bits = 0x0000ff;
} else if (mask & 0x00ff00) {
else if (mask & 0x00ff00)
bits = 0x00ff00;
} else if (mask & 0x0f0000) {
else if (mask & 0x0f0000)
bits = 0x0f0000;
} else {
else
bits = 0xf00000;
}
switch (data[0]) {
case INSN_CONFIG_DIO_INPUT:
@ -333,11 +333,10 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
return -ENOMEM;
CALLBACK_ARG = arg;
if (cb == NULL) {
if (cb == NULL)
CALLBACK_FUNC = subdev_8255_cb;
} else {
else
CALLBACK_FUNC = cb;
}
s->insn_bits = subdev_8255_insn;
s->insn_config = subdev_8255_insn_config;
@ -347,6 +346,7 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
EXPORT_SYMBOL(subdev_8255_init);
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
int (*cb) (int, int, int, unsigned long),
@ -366,6 +366,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
EXPORT_SYMBOL(subdev_8255_init_irq);
void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
{
@ -378,6 +379,7 @@ void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
kfree(s->private);
}
}
EXPORT_SYMBOL(subdev_8255_cleanup);
/*
@ -448,8 +450,3 @@ static int dev_8255_detach(struct comedi_device *dev)
return 0;
}
EXPORT_SYMBOL(subdev_8255_init);
EXPORT_SYMBOL(subdev_8255_init_irq);
EXPORT_SYMBOL(subdev_8255_cleanup);
EXPORT_SYMBOL(subdev_8255_interrupt);

View File

@ -94,10 +94,11 @@ static int acl7225b_attach(struct comedi_device *dev,
iobase = it->options[0];
iorange = this_board->io_range;
printk("comedi%d: acl7225b: board=%s 0x%04x ", dev->minor,
printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor,
this_board->name, iobase);
if (!request_region(iobase, iorange, "acl7225b")) {
printk("I/O port conflict\n");
printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n",
dev->minor);
return -EIO;
}
dev->board_name = this_board->name;
@ -137,14 +138,12 @@ static int acl7225b_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->private = (void *)ACL7225_DI_LO;
printk("\n");
return 0;
}
static int acl7225b_detach(struct comedi_device *dev)
{
printk("comedi%d: acl7225b: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);

View File

@ -1386,8 +1386,7 @@ int i_APCI1710_ReadChronoValue(struct comedi_device *dev,
/* Test the timout parameter */
/*****************************/
if ((ui_TimeOut >= 0)
&& (ui_TimeOut <= 65535UL)) {
if (ui_TimeOut <= 65535UL) {
for (;;) {
/*******************/

View File

@ -3807,7 +3807,7 @@ int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev,
s_ModuleInfo[b_ModulNbr].
s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
/********************************************/
/* Test if frequency mesurement initialised */
/* Test if frequency measurement initialised */
/********************************************/
if (devpriv->
@ -3953,7 +3953,7 @@ int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, unsigned c
s_ModuleInfo[b_ModulNbr].
s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
/********************************************/
/* Test if frequency mesurement initialised */
/* Test if frequency measurement initialised */
/********************************************/
if (devpriv->
@ -5166,7 +5166,7 @@ int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev,
s_ModuleInfo[b_ModulNbr].
s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
/********************************************/
/* Test if frequency mesurement initialised */
/* Test if frequency measurement initialised */
/********************************************/
if (devpriv->

View File

@ -1808,7 +1808,7 @@ int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device
2) {
if (dw_Status & 4) {
/************************/
/* Tor counter owerflow */
/* Tor counter overflow */
/************************/
*pb_TorCounterStatus

View File

@ -82,7 +82,7 @@ struct addi_board {
int i_NbrDiChannel; /* Number of DI channels */
int i_NbrDoChannel; /* Number of DO channels */
int i_DoMaxdata; /* data to set all chanels high */
int i_DoMaxdata; /* data to set all channels high */
int i_NbrTTLChannel; /* Number of TTL channels */
const struct comedi_lrange *pr_TTLRangelist; /* rangelist for TTL */

View File

@ -150,7 +150,7 @@ int i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdev
unsigned int ui_TmpValue = 0;
unsigned int ui_Channel;
ui_Channel = CR_CHAN(insn->chanspec);
if (ui_Channel >= 0 && ui_Channel <= 31) {
if (ui_Channel <= 31) {
ui_TmpValue = (unsigned int) inl(devpriv->iobase + APCI1032_DIGITAL_IP);
/*
* since only 1 channel reqd to bring it to last bit it is rotated 8

View File

@ -968,7 +968,7 @@ int i_APCI1500_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_sub
switch (data[0]) {
case 0:
if (ui_Channel >= 0 && ui_Channel <= 15) {
if (ui_Channel <= 15) {
ui_TmpValue =
(unsigned int) inw(devpriv->i_IobaseAddon +
APCI1500_DIGITAL_IP);

View File

@ -79,7 +79,7 @@ int i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdev
unsigned int ui_TmpValue = 0;
unsigned int ui_Channel;
ui_Channel = CR_CHAN(insn->chanspec);
if (ui_Channel >= 0 && ui_Channel <= 7) {
if (ui_Channel <= 7) {
ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI1516_DIGITAL_IP);
/* since only 1 channel reqd to bring it to last bit it is rotated */
/* 8 +(chan - 1) times then ANDed with 1 for last bit. */

View File

@ -154,7 +154,7 @@ int i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdev
unsigned int ui_Channel;
ui_Channel = CR_CHAN(insn->chanspec);
if (ui_Channel >= 0 && ui_Channel <= 31) {
if (ui_Channel <= 31) {
ui_TmpValue =
(unsigned int) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP);
/*

View File

@ -117,7 +117,7 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subde
unsigned int ui_NoOfChannel;
unsigned int ui_Temp, ui_Temp1;
ui_NoOfChannel = CR_CHAN(insn->chanspec);
if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) {
if (ui_NoOfChannel > 15) {
comedi_error(dev,
"Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
return -EINVAL;
@ -272,7 +272,7 @@ int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdev
unsigned int ui_Temp;
unsigned int ui_NoOfChannel;
ui_NoOfChannel = CR_CHAN(insn->chanspec);
if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) {
if (ui_NoOfChannel > 15) {
comedi_error(dev,
"Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
return -EINVAL;

View File

@ -79,7 +79,7 @@ int i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdev
unsigned int ui_TmpValue = 0;
unsigned int ui_Channel;
ui_Channel = CR_CHAN(insn->chanspec);
if (ui_Channel >= 0 && ui_Channel <= 7) {
if (ui_Channel <= 7) {
ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI2200_DIGITAL_IP);
*data = (ui_TmpValue >> ui_Channel) & 0x1;
} /* if(ui_Channel >= 0 && ui_Channel <=7) */

View File

@ -1468,7 +1468,7 @@ void v_APCI3120_Interrupt(int irq, void *d)
int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
comedi_error(dev, "IRQ from unknow source");
comedi_error(dev, "IRQ from unknown source");
return;
}
@ -2350,7 +2350,7 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
/* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
if (ui_Chan >= 0 && ui_Chan <= 3) {
if (ui_Chan <= 3) {
ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
/*
@ -2539,8 +2539,7 @@ int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
"Not a valid Data !!! ,Data should be 1 or 0\n");
return -EINVAL;
}
if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
|| (ui_NoOfChannel < 0)) {
if (ui_NoOfChannel > this_board->i_NbrDoChannel - 1) {
comedi_error(dev,
"This board doesn't have specified channel !!! \n");
return -EINVAL;

View File

@ -461,7 +461,7 @@ int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev,
if (s_BoardInfos[dev->minor].i_ConnectionType == 1) {
/* if diff */
if ((ui_Channel_num >= 0) && (ui_Channel_num <= 1))
if (ui_Channel_num <= 1)
i_DiffChannel = ui_Channel_num, i_Module = 0;
else if ((ui_Channel_num >= 2) && (ui_Channel_num <= 3))
i_DiffChannel = ui_Channel_num - 2, i_Module = 1;

View File

@ -724,7 +724,7 @@ void v_APCI3501_Interrupt(int irq, void *d)
APCI3501_TCW_IRQ) & 0x1;
if ((!ui_Timer_AOWatchdog)) {
comedi_error(dev, "IRQ from unknow source");
comedi_error(dev, "IRQ from unknown source");
return;
}

View File

@ -148,7 +148,7 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device *dev,
/* Test the convert time value */
/*******************************/
if ((dw_ReloadValue >= 0) && (dw_ReloadValue <= 65535)) {
if (dw_ReloadValue <= 65535) {
dw_TestReloadValue = dw_ReloadValue;
if (b_TimeBase == 1) {

View File

@ -133,9 +133,11 @@ static int pci6208_ao_winsn(struct comedi_device *dev,
static int pci6208_ao_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
/* static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, */
/* static int pci6208_dio_insn_bits (struct comedi_device *dev,
* struct comedi_subdevice *s, */
/* struct comedi_insn *insn,unsigned int *data); */
/* static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, */
/* static int pci6208_dio_insn_config(struct comedi_device *dev,
* struct comedi_subdevice *s, */
/* struct comedi_insn *insn,unsigned int *data); */
/*
@ -151,7 +153,7 @@ static int pci6208_attach(struct comedi_device *dev,
int retval;
unsigned long io_base;
printk("comedi%d: pci6208: ", dev->minor);
printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
retval = alloc_private(dev, sizeof(struct pci6208_private));
if (retval < 0)
@ -195,7 +197,7 @@ static int pci6208_attach(struct comedi_device *dev,
/* s->insn_bits = pci6208_dio_insn_bits; */
/* s->insn_config = pci6208_dio_insn_config; */
printk("attached\n");
printk(KERN_INFO "attached\n");
return 1;
}
@ -210,12 +212,11 @@ static int pci6208_attach(struct comedi_device *dev,
*/
static int pci6208_detach(struct comedi_device *dev)
{
printk("comedi%d: pci6208: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor);
if (devpriv && devpriv->pci_dev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
}
@ -266,7 +267,8 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
* useful to applications if you implement the insn_bits interface.
* This allows packed reading/writing of the DIO channels. The
* comedi core can convert between insn_bits and insn_read/write */
/* static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, */
/* static int pci6208_dio_insn_bits(struct comedi_device *dev,
* struct comedi_subdevice *s, */
/* struct comedi_insn *insn,unsigned int *data) */
/* { */
/* if(insn->n!=2)return -EINVAL; */
@ -290,7 +292,8 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
/* return 2; */
/* } */
/* static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, */
/* static int pci6208_dio_insn_config(struct comedi_device *dev,
* struct comedi_subdevice *s, */
/* struct comedi_insn *insn,unsigned int *data) */
/* { */
/* int chan=CR_CHAN(insn->chanspec); */
@ -320,10 +323,16 @@ static int pci6208_find_device(struct comedi_device *dev, int bus, int slot)
pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) {
if (pci_dev->vendor == PCI_VENDOR_ID_ADLINK) {
for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
if (pci6208_boards[i].dev_id == pci_dev->device) {
/* was a particular bus/slot requested? */
if (pci6208_boards[i].dev_id ==
pci_dev->device) {
/*
* was a particular bus/slot requested?
*/
if ((bus != 0) || (slot != 0)) {
/* are we on the wrong bus/slot? */
/*
* are we on the
* wrong bus/slot?
*/
if (pci_dev->bus->number
!= bus ||
PCI_SLOT(pci_dev->devfn)
@ -338,8 +347,9 @@ static int pci6208_find_device(struct comedi_device *dev, int bus, int slot)
}
}
printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
dev->minor, bus, slot);
printk(KERN_ERR "comedi%d: no supported board found! "
"(req. bus/slot : %d/%d)\n",
dev->minor, bus, slot);
return -EIO;
found:
@ -368,17 +378,20 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
/* Enable PCI device and request regions */
if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) {
printk
("comedi%d: Failed to enable PCI device and request regions\n",
dev_minor);
printk(KERN_ERR "comedi%d: Failed to enable PCI device "
"and request regions\n",
dev_minor);
return -EIO;
}
/* Read local configuration register base address [PCI_BASE_ADDRESS #1]. */
/* Read local configuration register
* base address [PCI_BASE_ADDRESS #1].
*/
lcr_io_base = pci_resource_start(pci_dev, 1);
lcr_io_range = pci_resource_len(pci_dev, 1);
printk("comedi%d: local config registers at address 0x%4lx [0x%4lx]\n",
dev_minor, lcr_io_base, lcr_io_range);
printk(KERN_INFO "comedi%d: local config registers at address"
" 0x%4lx [0x%4lx]\n",
dev_minor, lcr_io_base, lcr_io_range);
/* Read PCI6208 register base address [PCI_BASE_ADDRESS #2]. */
io_base = pci_resource_start(pci_dev, 2);

View File

@ -82,8 +82,7 @@ static int adl_pci7296_attach(struct comedi_device *dev,
int bus, slot;
int ret;
printk("comedi: attempt to attach...\n");
printk("comedi%d: adl_pci7432\n", dev->minor);
printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
dev->board_name = "pci7432";
bus = it->options[0];
@ -110,14 +109,14 @@ static int adl_pci7296_attach(struct comedi_device *dev,
}
devpriv->pci_dev = pcidev;
if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) {
printk
("comedi%d: Failed to enable PCI device and request regions\n",
printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
dev->minor);
return -EIO;
}
dev->iobase = pci_resource_start(pcidev, 2);
printk("comedi: base addr %4lx\n", dev->iobase);
printk(KERN_INFO "comedi: base addr %4lx\n",
dev->iobase);
/* four 8255 digital io subdevices */
s = dev->subdevices + 0;
@ -145,25 +144,25 @@ static int adl_pci7296_attach(struct comedi_device *dev,
if (ret < 0)
return ret;
printk("attached\n");
printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n",
dev->minor);
return 1;
}
}
printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
dev->minor, bus, slot);
return -EIO;
}
static int adl_pci7296_detach(struct comedi_device *dev)
{
printk("comedi%d: pci7432: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
if (devpriv && devpriv->pci_dev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
}
/* detach four 8255 digital io subdevices */

View File

@ -90,8 +90,7 @@ static int adl_pci7432_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int bus, slot;
printk("comedi: attempt to attach...\n");
printk("comedi%d: adl_pci7432\n", dev->minor);
printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
dev->board_name = "pci7432";
bus = it->options[0];
@ -118,13 +117,13 @@ static int adl_pci7432_attach(struct comedi_device *dev,
}
devpriv->pci_dev = pcidev;
if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) {
printk
("comedi%d: Failed to enable PCI device and request regions\n",
printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
dev->minor);
return -EIO;
}
dev->iobase = pci_resource_start(pcidev, 2);
printk("comedi: base addr %4lx\n", dev->iobase);
printk(KERN_INFO "comedi: base addr %4lx\n",
dev->iobase);
s = dev->subdevices + 0;
s->type = COMEDI_SUBD_DI;
@ -148,25 +147,24 @@ static int adl_pci7432_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = adl_pci7432_do_insn_bits;
printk("comedi: attached\n");
printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n",
dev->minor);
return 1;
}
}
printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
dev->minor, bus, slot);
return -EIO;
}
static int adl_pci7432_detach(struct comedi_device *dev)
{
printk("comedi%d: pci7432: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
if (devpriv && devpriv->pci_dev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
}
@ -178,8 +176,8 @@ static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
printk("comedi: pci7432_do_insn_bits called\n");
printk("comedi: data0: %8x data1: %8x\n", data[0], data[1]);
printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
if (insn->n != 2)
return -EINVAL;
@ -188,7 +186,7 @@ static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
s->state &= ~data[0];
s->state |= (data[0] & data[1]);
printk("comedi: out: %8x on iobase %4lx\n", s->state,
printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
dev->iobase + PCI7432_DO);
outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
}
@ -200,14 +198,14 @@ static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
printk("comedi: pci7432_di_insn_bits called\n");
printk("comedi: data0: %8x data1: %8x\n", data[0], data[1]);
printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
if (insn->n != 2)
return -EINVAL;
data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
printk("comedi: data1 %8x\n", data[1]);
printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
return 2;
}

View File

@ -35,6 +35,7 @@ Configuration Options:
*/
#include "../comedidev.h"
#include <linux/kernel.h>
#include <linux/delay.h>
#include "comedi_fc.h"
#include "comedi_pci.h"
@ -128,8 +129,8 @@ static int adl_pci8164_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int bus, slot;
printk("comedi: attempt to attach...\n");
printk("comedi%d: adl_pci8164\n", dev->minor);
printk(KERN_INFO "comedi: attempt to attach...\n");
printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
dev->board_name = "pci8164";
bus = it->options[0];
@ -150,19 +151,18 @@ static int adl_pci8164_attach(struct comedi_device *dev,
if (bus || slot) {
/* requested particular bus/slot */
if (pcidev->bus->number != bus
|| PCI_SLOT(pcidev->devfn) != slot) {
|| PCI_SLOT(pcidev->devfn) != slot)
continue;
}
}
devpriv->pci_dev = pcidev;
if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
printk
("comedi%d: Failed to enable PCI device and request regions\n",
dev->minor);
printk(KERN_ERR "comedi%d: Failed to enable "
"PCI device and request regions\n", dev->minor);
return -EIO;
}
dev->iobase = pci_resource_start(pcidev, 2);
printk("comedi: base addr %4lx\n", dev->iobase);
printk(KERN_DEBUG "comedi: base addr %4lx\n",
dev->iobase);
s = dev->subdevices + 0;
s->type = COMEDI_SUBD_PROC;
@ -204,25 +204,24 @@ static int adl_pci8164_attach(struct comedi_device *dev,
s->insn_read = adl_pci8164_insn_read_buf1;
s->insn_write = adl_pci8164_insn_write_buf1;
printk("comedi: attached\n");
printk(KERN_INFO "comedi: attached\n");
return 1;
}
}
printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
dev->minor, bus, slot);
printk(KERN_ERR "comedi%d: no supported board found!"
"(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
return -EIO;
}
static int adl_pci8164_detach(struct comedi_device *dev)
{
printk("comedi%d: pci8164: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor);
if (devpriv && devpriv->pci_dev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
}
@ -267,8 +266,9 @@ static void adl_pci8164_insn_read(struct comedi_device *dev,
}
data[0] = inw(dev->iobase + axis_reg + offset);
printk("comedi: pci8164 %s read -> %04X:%04X on axis %s\n", action,
data[0], data[1], axisname);
printk(KERN_DEBUG "comedi: pci8164 %s read -> "
"%04X:%04X on axis %s\n",
action, data[0], data[1], axisname);
}
static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
@ -347,8 +347,9 @@ static void adl_pci8164_insn_out(struct comedi_device *dev,
outw(data[0], dev->iobase + axis_reg + offset);
printk("comedi: pci8164 %s write -> %04X:%04X on axis %s\n", action,
data[0], data[1], axisname);
printk(KERN_DEBUG "comedi: pci8164 %s write -> "
"%04X:%04X on axis %s\n",
action, data[0], data[1], axisname);
}

View File

@ -780,7 +780,7 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
int err = 0;
int tmp, divisor1, divisor2;
int tmp, divisor1 = 0, divisor2 = 0;
/* step 1: make sure trigger sources are trivially valid */

View File

@ -830,7 +830,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
struct comedi_subdevice *s)
{
unsigned int divisor1, divisor2;
unsigned int divisor1 = 0, divisor2 = 0;
unsigned int seglen;
DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
@ -934,7 +934,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
int err = 0;
int tmp, divisor1, divisor2;
int tmp, divisor1 = 0, divisor2 = 0;
DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
#ifdef PCI171X_EXTDEBUG

View File

@ -117,7 +117,8 @@ MODULE_DEVICE_TABLE(pci, pc263_pci_table);
/* this structure is for data unique to this hardware driver. If
several hardware drivers keep similar information in this structure,
feel free to suggest moving the variable to the struct comedi_device struct. */
feel free to suggest moving the variable to the struct comedi_device struct.
*/
#ifdef CONFIG_COMEDI_PCI
struct pc263_private {
/* PCI device. */
@ -281,7 +282,8 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
if (ret < 0) {
printk(KERN_ERR
"comedi%d: error! cannot enable PCI device and request regions!\n",
"comedi%d: error! cannot enable PCI device and "
"request regions!\n",
dev->minor);
return ret;
}
@ -290,9 +292,8 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
{
ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
if (ret < 0) {
if (ret < 0)
return ret;
}
}
dev->iobase = iobase;
@ -350,21 +351,18 @@ static int pc263_detach(struct comedi_device *dev)
PC263_DRIVER_NAME);
#ifdef CONFIG_COMEDI_PCI
if (devpriv)
if (devpriv) {
#endif
{
#ifdef CONFIG_COMEDI_PCI
if (devpriv->pci_dev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
} else
#endif
{
if (dev->iobase) {
if (dev->iobase)
release_region(dev->iobase, PC263_IO_SIZE);
}
}
}
if (dev->board_name) {

View File

@ -372,7 +372,7 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER &&
cmd->scan_begin_src != TRIG_EXT)
err++;
@ -452,7 +452,7 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
unsigned int div1, div2;
unsigned int div1 = 0, div2 = 0;
tmp = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(100, &div1, &div2,
@ -462,7 +462,7 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev,
err++;
}
if (cmd->convert_src == TRIG_TIMER) {
unsigned int div1, div2;
unsigned int div1 = 0, div2 = 0;
tmp = cmd->convert_arg;
i8253_cascade_ns_to_timer(100, &div1, &div2,

View File

@ -497,7 +497,7 @@ static int cb_pcidda_ai_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER
&& cmd->scan_begin_src != TRIG_EXT)
err++;

View File

@ -109,12 +109,12 @@ MODULE_DEVICE_TABLE(pci, pcidio_pci_table);
several hardware drivers keep similar information in this structure,
feel free to suggest moving the variable to the struct comedi_device struct. */
struct pcidio_private {
int data; /* curently unused */
int data; /* currently unused */
/* would be useful for a PCI device */
struct pci_dev *pci_dev;
/* used for DO readback, curently unused */
/* used for DO readback, currently unused */
unsigned int do_readback[4]; /* up to 4 unsigned int suffice to hold 96 bits for PCI-DIO96 */
unsigned long dio_reg_base; /* address of port A of the first 8255 chip on board */

View File

@ -53,7 +53,7 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
retval = comedi_buf_write_alloc(async, num_bytes);
if (retval != num_bytes) {
printk("comedi: buffer overrun\n");
printk(KERN_WARNING "comedi: buffer overrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return 0;
}
@ -65,7 +65,6 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
return num_bytes;
}
EXPORT_SYMBOL(cfc_write_array_to_buffer);
unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
@ -84,7 +83,6 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
return num_bytes;
}
EXPORT_SYMBOL(cfc_read_array_from_buffer);
unsigned int cfc_handle_events(struct comedi_device *dev,
@ -102,7 +100,6 @@ unsigned int cfc_handle_events(struct comedi_device *dev,
return events;
}
EXPORT_SYMBOL(cfc_handle_events);
MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");

View File

@ -629,7 +629,7 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER &&
cmd->scan_begin_src != TRIG_EXT)
err++;

View File

@ -175,7 +175,7 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
err++;

View File

@ -777,7 +777,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_FOLLOW &&
cmd->scan_begin_src != TRIG_EXT)
err++;
@ -1050,7 +1050,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev,
/* step 2: make sure trigger sources are unique and mutually compatible */
/* note that mutual compatiblity is not an issue here */
/* note that mutual compatibility is not an issue here */
if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
err++;

View File

@ -55,7 +55,7 @@ support could be added to this driver.
static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it);
static int hpdi_detach(struct comedi_device *dev);
void abort_dma(struct comedi_device *dev, unsigned int channel);
static void abort_dma(struct comedi_device *dev, unsigned int channel);
static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd);
@ -110,7 +110,8 @@ enum hpdi_registers {
int command_channel_valid(unsigned int channel)
{
if (channel == 0 || channel > 6) {
printk("gsc_hpdi: bug! invalid cable command channel\n");
printk(KERN_WARNING
"gsc_hpdi: bug! invalid cable command channel\n");
return 0;
}
return 1;
@ -142,7 +143,8 @@ enum board_control_bits {
RX_FIFO_RESET_BIT = 0x4,
TX_ENABLE_BIT = 0x10,
RX_ENABLE_BIT = 0x20,
DEMAND_DMA_DIRECTION_TX_BIT = 0x40, /* for channel 0, channel 1 can only transmit (when present) */
DEMAND_DMA_DIRECTION_TX_BIT = 0x40,
/* for ch 0, ch 1 can only transmit (when present) */
LINE_VALID_ON_STATUS_VALID_BIT = 0x80,
START_TX_BIT = 0x10,
CABLE_THROTTLE_ENABLE_BIT = 0x20,
@ -420,9 +422,11 @@ static void init_plx9080(struct comedi_device *dev)
bits |= PLX_DMA_EN_READYIN_BIT;
/* enable dma chaining */
bits |= PLX_EN_CHAIN_BIT;
/* enable interrupt on dma done (probably don't need this, since chain never finishes) */
/* enable interrupt on dma done
* (probably don't need this, since chain never finishes) */
bits |= PLX_EN_DMA_DONE_INTR_BIT;
/* don't increment local address during transfers (we are transferring from a fixed fifo register) */
/* don't increment local address during transfers
* (we are transferring from a fixed fifo register) */
bits |= PLX_LOCAL_ADDR_CONST_BIT;
/* route dma interrupt to pci bus */
bits |= PLX_DMA_INTR_PCI_BIT;
@ -560,7 +564,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i;
int retval;
printk("comedi%d: gsc_hpdi\n", dev->minor);
printk(KERN_WARNING "comedi%d: gsc_hpdi\n", dev->minor);
if (alloc_private(dev, sizeof(struct hpdi_private)) < 0)
return -ENOMEM;
@ -588,11 +592,12 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} while (pcidev != NULL);
}
if (dev->board_ptr == NULL) {
printk("gsc_hpdi: no hpdi card found\n");
printk(KERN_WARNING "gsc_hpdi: no hpdi card found\n");
return -EIO;
}
printk("gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name,
printk(KERN_WARNING
"gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) {
@ -618,7 +623,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ioremap(priv(dev)->hpdi_phys_iobase,
pci_resource_len(pcidev, HPDI_BADDRINDEX));
if (!priv(dev)->plx9080_iobase || !priv(dev)->hpdi_iobase) {
printk(" failed to remap io memory\n");
printk(KERN_WARNING " failed to remap io memory\n");
return -ENOMEM;
}
@ -630,12 +635,13 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* get irq */
if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
driver_hpdi.driver_name, dev)) {
printk(" unable to allocate irq %u\n", pcidev->irq);
printk(KERN_WARNING
" unable to allocate irq %u\n", pcidev->irq);
return -EINVAL;
}
dev->irq = pcidev->irq;
printk(" irq %u\n", dev->irq);
printk(KERN_WARNING " irq %u\n", dev->irq);
/* alocate pci dma buffers */
for (i = 0; i < NUM_DMA_BUFFERS; i++) {
@ -653,7 +659,8 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
&priv(dev)->
dma_desc_phys_addr);
if (priv(dev)->dma_desc_phys_addr & 0xf) {
printk(" dma descriptors not quad-word aligned (bug)\n");
printk(KERN_WARNING
" dma descriptors not quad-word aligned (bug)\n");
return -EIO;
}
@ -672,42 +679,39 @@ static int hpdi_detach(struct comedi_device *dev)
{
unsigned int i;
printk("comedi%d: gsc_hpdi: remove\n", dev->minor);
printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor);
if (dev->irq)
free_irq(dev->irq, dev);
if (priv(dev)) {
if (priv(dev)->hw_dev) {
if (priv(dev)->plx9080_iobase) {
disable_plx_interrupts(dev);
iounmap((void *)priv(dev)->plx9080_iobase);
}
if (priv(dev)->hpdi_iobase)
iounmap((void *)priv(dev)->hpdi_iobase);
/* free pci dma buffers */
for (i = 0; i < NUM_DMA_BUFFERS; i++) {
if (priv(dev)->dio_buffer[i])
pci_free_consistent(priv(dev)->hw_dev,
DMA_BUFFER_SIZE,
priv(dev)->
dio_buffer[i],
priv
(dev)->dio_buffer_phys_addr
[i]);
}
/* free dma descriptors */
if (priv(dev)->dma_desc)
pci_free_consistent(priv(dev)->hw_dev,
sizeof(struct plx_dma_desc)
* NUM_DMA_DESCRIPTORS,
priv(dev)->dma_desc,
priv(dev)->
dma_desc_phys_addr);
if (priv(dev)->hpdi_phys_iobase) {
comedi_pci_disable(priv(dev)->hw_dev);
}
pci_dev_put(priv(dev)->hw_dev);
if ((priv(dev)) && (priv(dev)->hw_dev)) {
if (priv(dev)->plx9080_iobase) {
disable_plx_interrupts(dev);
iounmap((void *)priv(dev)->plx9080_iobase);
}
if (priv(dev)->hpdi_iobase)
iounmap((void *)priv(dev)->hpdi_iobase);
/* free pci dma buffers */
for (i = 0; i < NUM_DMA_BUFFERS; i++) {
if (priv(dev)->dio_buffer[i])
pci_free_consistent(priv(dev)->hw_dev,
DMA_BUFFER_SIZE,
priv(dev)->
dio_buffer[i],
priv
(dev)->dio_buffer_phys_addr
[i]);
}
/* free dma descriptors */
if (priv(dev)->dma_desc)
pci_free_consistent(priv(dev)->hw_dev,
sizeof(struct plx_dma_desc)
* NUM_DMA_DESCRIPTORS,
priv(dev)->dma_desc,
priv(dev)->
dma_desc_phys_addr);
if (priv(dev)->hpdi_phys_iobase)
comedi_pci_disable(priv(dev)->hw_dev);
pci_dev_put(priv(dev)->hw_dev);
}
return 0;
}
@ -810,15 +814,16 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 4;
if (cmd->chanlist) {
for (i = 1; i < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i]) != i) {
/* XXX could support 8 channels or 16 channels */
comedi_error(dev,
"chanlist must be channels 0 to 31 in order");
err++;
break;
}
if (!cmd->chanlist)
return 0;
for (i = 1; i < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i]) != i) {
/* XXX could support 8 or 16 channels */
comedi_error(dev,
"chanlist must be ch 0 to 31 in order");
err++;
break;
}
}
@ -831,9 +836,9 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
if (priv(dev)->dio_config_output) {
if (priv(dev)->dio_config_output)
return -EINVAL;
} else
else
return di_cmd_test(dev, s, cmd);
}
@ -899,9 +904,9 @@ static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
if (priv(dev)->dio_config_output) {
if (priv(dev)->dio_config_output)
return -EINVAL;
} else
else
return di_cmd(dev, s);
}
@ -963,14 +968,12 @@ static irqreturn_t handle_interrupt(int irq, void *d)
uint8_t dma0_status, dma1_status;
unsigned long flags;
if (!dev->attached) {
if (!dev->attached)
return IRQ_NONE;
}
plx_status = readl(priv(dev)->plx9080_iobase + PLX_INTRCS_REG);
if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) {
if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0)
return IRQ_NONE;
}
hpdi_intr_status = readl(priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG);
hpdi_board_status = readl(priv(dev)->hpdi_iobase + BOARD_STATUS_REG);
@ -990,9 +993,8 @@ static irqreturn_t handle_interrupt(int irq, void *d)
priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);
if (dma0_status & PLX_DMA_EN_BIT) {
if (dma0_status & PLX_DMA_EN_BIT)
drain_dma_buffers(dev, 0);
}
DEBUG_PRINT(" cleared dma ch0 interrupt\n");
}
spin_unlock_irqrestore(&dev->spinlock, flags);
@ -1042,7 +1044,7 @@ static irqreturn_t handle_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
void abort_dma(struct comedi_device *dev, unsigned int channel)
static void abort_dma(struct comedi_device *dev, unsigned int channel)
{
unsigned long flags;

View File

@ -46,7 +46,7 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V
Options:
[0] - PCI bus number - if bus number and slot number are 0,
then driver search for first unused card
then driver search for first unused card
[1] - PCI slot number
*/
@ -133,7 +133,7 @@ static int icp_multi_detach(struct comedi_device *dev);
Data & Structure declarations
==============================================================================
*/
static unsigned short pci_list_builded = 0; /*>0 list of card is known */
static unsigned short pci_list_builded; /*>0 list of card is known */
struct boardtype {
const char *name; /* driver name */
@ -176,13 +176,13 @@ static const struct boardtype boardtypes[] = {
#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
static struct comedi_driver driver_icp_multi = {
driver_name:"icp_multi",
module:THIS_MODULE,
attach:icp_multi_attach,
detach:icp_multi_detach,
num_names:n_boardtypes,
board_name:&boardtypes[0].name,
offset:sizeof(struct boardtype),
driver_name: "icp_multi",
module : THIS_MODULE,
attach : icp_multi_attach,
detach : icp_multi_detach,
num_names : n_boardtypes,
board_name : &boardtypes[0].name,
offset : sizeof(struct boardtype),
};
COMEDI_INITCLEANUP(driver_icp_multi);
@ -234,18 +234,18 @@ static int icp_multi_reset(struct comedi_device *dev);
/*
==============================================================================
Name: icp_multi_insn_read_ai
Name: icp_multi_insn_read_ai
Description:
This function reads a single analogue input.
Description:
This function reads a single analogue input.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue input data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue input data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -256,7 +256,7 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
int n, timeout;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n");
printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n");
#endif
/* Disable A/D conversion ready interrupt */
devpriv->IntEnable &= ~ADC_READY;
@ -266,11 +266,11 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
devpriv->IntStatus |= ADC_READY;
writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
/* Set up appropriate channel, mode and range data, for specified channel */
/* Set up appropriate channel, mode and range data, for specified ch */
setup_channel_list(dev, s, &insn->chanspec, 1);
#ifdef ICP_MULTI_EXTDEBUG
printk("icp_multi A ST=%4x IO=%p\n",
printk(KERN_DEBUG "icp_multi A ST=%4x IO=%p\n",
readw(devpriv->io_addr + ICP_MULTI_ADC_CSR),
devpriv->io_addr + ICP_MULTI_ADC_CSR);
#endif
@ -283,14 +283,14 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
devpriv->AdcCmdStatus &= ~ADC_ST;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi B n=%d ST=%4x\n", n,
printk(KERN_DEBUG "icp multi B n=%d ST=%4x\n", n,
readw(devpriv->io_addr + ICP_MULTI_ADC_CSR));
#endif
udelay(1);
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi C n=%d ST=%4x\n", n,
printk(KERN_DEBUG "icp multi C n=%d ST=%4x\n", n,
readw(devpriv->io_addr + ICP_MULTI_ADC_CSR));
#endif
@ -303,7 +303,8 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
#ifdef ICP_MULTI_EXTDEBUG
if (!(timeout % 10))
printk("icp multi D n=%d tm=%d ST=%4x\n", n,
printk(KERN_DEBUG
"icp multi D n=%d tm=%d ST=%4x\n", n,
timeout,
readw(devpriv->io_addr +
ICP_MULTI_ADC_CSR));
@ -328,9 +329,9 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
data[n] = 0;
#ifdef ICP_MULTI_EXTDEBUG
printk
("icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n",
n);
printk(KERN_DEBUG
"icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n",
n);
#endif
return -ETIME;
@ -348,7 +349,8 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", n);
printk(KERN_DEBUG
"icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", n);
#endif
return n;
}
@ -356,18 +358,18 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_write_ao
Name: icp_multi_insn_write_ao
Description:
This function writes a single analogue output.
Description:
This function writes a single analogue output.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -378,7 +380,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
int n, chan, range, timeout;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n");
printk(KERN_DEBUG
"icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n");
#endif
/* Disable D/A conversion ready interrupt */
devpriv->IntEnable &= ~DAC_READY;
@ -404,7 +407,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR);
for (n = 0; n < insn->n; n++) {
/* Wait for analogue output data register to be ready for new data, or get fed up waiting */
/* Wait for analogue output data register to be
* ready for new data, or get fed up waiting */
timeout = 100;
while (timeout--) {
if (!(readw(devpriv->io_addr +
@ -413,7 +417,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
#ifdef ICP_MULTI_EXTDEBUG
if (!(timeout % 10))
printk("icp multi A n=%d tm=%d ST=%4x\n", n,
printk(KERN_DEBUG
"icp multi A n=%d tm=%d ST=%4x\n", n,
timeout,
readw(devpriv->io_addr +
ICP_MULTI_DAC_CSR));
@ -438,8 +443,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
devpriv->ao_data[chan] = 0;
#ifdef ICP_MULTI_EXTDEBUG
printk
("icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n",
printk(KERN_DEBUG
"icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n",
n);
#endif
return -ETIME;
@ -459,7 +464,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
}
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", n);
printk(KERN_DEBUG
"icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", n);
#endif
return n;
}
@ -467,18 +473,18 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_read_ao
Name: icp_multi_insn_read_ao
Description:
This function reads a single analogue output.
Description:
This function reads a single analogue output.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -501,18 +507,18 @@ static int icp_multi_insn_read_ao(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_bits_di
Name: icp_multi_insn_bits_di
Description:
This function reads the digital inputs.
Description:
This function reads the digital inputs.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -528,18 +534,18 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_bits_do
Name: icp_multi_insn_bits_do
Description:
This function writes the appropriate digital outputs.
Description:
This function writes the appropriate digital outputs.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to analogue output data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -548,14 +554,14 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n");
printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n");
#endif
if (data[0]) {
s->state &= ~data[0];
s->state |= (data[0] & data[1]);
printk("Digital outputs = %4x \n", s->state);
printk(KERN_DEBUG "Digital outputs = %4x \n", s->state);
writew(s->state, devpriv->io_addr + ICP_MULTI_DO);
}
@ -563,7 +569,7 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev,
data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: icp_multi_insn_bits_do(...)\n");
printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_insn_bits_do(...)\n");
#endif
return 2;
}
@ -571,18 +577,18 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_read_ctr
Name: icp_multi_insn_read_ctr
Description:
This function reads the specified counter.
Description:
This function reads the specified counter.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to counter data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to counter data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -596,18 +602,18 @@ static int icp_multi_insn_read_ctr(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_insn_write_ctr
Name: icp_multi_insn_write_ctr
Description:
This function write to the specified counter.
Description:
This function write to the specified counter.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to counter data
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_subdevice *s Pointer to current subdevice structure
struct comedi_insn *insn Pointer to current comedi instruction
unsigned int *data Pointer to counter data
Returns:int Nmuber of instructions executed
Returns:int Nmuber of instructions executed
==============================================================================
*/
@ -622,15 +628,15 @@ static int icp_multi_insn_write_ctr(struct comedi_device *dev,
/*
==============================================================================
Name: interrupt_service_icp_multi
Name: interrupt_service_icp_multi
Description:
This function is the interrupt service routine for all
interrupts generated by the icp multi board.
Description:
This function is the interrupt service routine for all
interrupts generated by the icp multi board.
Parameters:
int irq
void *d Pointer to current device
Parameters:
int irq
void *d Pointer to current device
==============================================================================
*/
@ -640,7 +646,8 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
int int_no;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n",
printk(KERN_DEBUG
"icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n",
irq);
#endif
@ -651,7 +658,8 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
return IRQ_NONE;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n",
printk(KERN_DEBUG
"icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n",
readw(devpriv->io_addr + ICP_MULTI_INT_STAT));
#endif
@ -679,7 +687,8 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
}
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: interrupt_service_icp_multi(...)\n");
printk(KERN_DEBUG
"icp multi EDBG: END: interrupt_service_icp_multi(...)\n");
#endif
return IRQ_HANDLED;
}
@ -688,20 +697,20 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
/*
==============================================================================
Name: check_channel_list
Name: check_channel_list
Description:
This function checks if the channel list, provided by user
is built correctly
Description:
This function checks if the channel list, provided by user
is built correctly
Parameters:
struct comedi_device *dev Pointer to current sevice structure
struct comedi_subdevice *s Pointer to current subdevice structure
unsigned int *chanlist Pointer to packed channel list
unsigned int n_chan Number of channels to scan
Parameters:
struct comedi_device *dev Pointer to current sevice structure
struct comedi_subdevice *s Pointer to current subdevice structure
unsigned int *chanlist Pointer to packed channel list
unsigned int n_chan Number of channels to scan
Returns:int 0 = failure
1 = success
Returns:int 0 = failure
1 = success
==============================================================================
*/
@ -712,7 +721,8 @@ static int check_channel_list(struct comedi_device *dev,
unsigned int i;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: check_channel_list(...,%d)\n", n_chan);
printk(KERN_DEBUG
"icp multi EDBG: check_channel_list(...,%d)\n", n_chan);
#endif
/* Check that we at least have one channel to check */
if (n_chan < 1) {
@ -725,7 +735,7 @@ static int check_channel_list(struct comedi_device *dev,
if (CR_AREF(chanlist[i]) == AREF_DIFF) {
if (CR_CHAN(chanlist[i]) > this_board->n_aichand) {
comedi_error(dev,
"Incorrect differential ai channel number");
"Incorrect differential ai ch-nr");
return 0;
}
} else {
@ -743,20 +753,20 @@ static int check_channel_list(struct comedi_device *dev,
/*
==============================================================================
Name: setup_channel_list
Name: setup_channel_list
Description:
This function sets the appropriate channel selection,
differential input mode and range bits in the ADC Command/
Status register.
Description:
This function sets the appropriate channel selection,
differential input mode and range bits in the ADC Command/
Status register.
Parameters:
struct comedi_device *dev Pointer to current sevice structure
struct comedi_subdevice *s Pointer to current subdevice structure
unsigned int *chanlist Pointer to packed channel list
unsigned int n_chan Number of channels to scan
Parameters:
struct comedi_device *dev Pointer to current sevice structure
struct comedi_subdevice *s Pointer to current subdevice structure
unsigned int *chanlist Pointer to packed channel list
unsigned int n_chan Number of channels to scan
Returns:Void
Returns:Void
==============================================================================
*/
@ -768,7 +778,8 @@ static void setup_channel_list(struct comedi_device *dev,
unsigned int diff;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
printk(KERN_DEBUG
"icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
#endif
devpriv->act_chanlist_len = n_chan;
devpriv->act_chanlist_pos = 0;
@ -786,7 +797,8 @@ static void setup_channel_list(struct comedi_device *dev,
chanprog &= 0x000f;
}
/* Clear channel, range and input mode bits in A/D command/status register */
/* Clear channel, range and input mode bits
* in A/D command/status register */
devpriv->AdcCmdStatus &= 0xf00f;
/* Set channel number and differential mode status bit */
@ -808,7 +820,8 @@ static void setup_channel_list(struct comedi_device *dev,
devpriv->io_addr + ICP_MULTI_ADC_CSR);
#ifdef ICP_MULTI_EXTDEBUG
printk("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
printk(KERN_DEBUG
"GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
devpriv->act_chanlist[i]);
#endif
}
@ -818,15 +831,15 @@ static void setup_channel_list(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_reset
Name: icp_multi_reset
Description:
This function resets the icp multi device to a 'safe' state
Description:
This function resets the icp multi device to a 'safe' state
Parameters:
struct comedi_device *dev Pointer to current sevice structure
Parameters:
struct comedi_device *dev Pointer to current sevice structure
Returns:int 0 = success
Returns:int 0 = success
==============================================================================
*/
@ -835,7 +848,8 @@ static int icp_multi_reset(struct comedi_device *dev)
unsigned int i;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp_multi EDBG: BGN: icp_multi_reset(...)\n");
printk(KERN_DEBUG
"icp_multi EDBG: BGN: icp_multi_reset(...)\n");
#endif
/* Clear INT enables and requests */
writew(0, devpriv->io_addr + ICP_MULTI_INT_EN);
@ -866,7 +880,8 @@ static int icp_multi_reset(struct comedi_device *dev)
writew(0, devpriv->io_addr + ICP_MULTI_DO);
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: icp_multi_reset(...)\n");
printk(KERN_DEBUG
"icp multi EDBG: END: icp_multi_reset(...)\n");
#endif
return 0;
}
@ -874,17 +889,17 @@ static int icp_multi_reset(struct comedi_device *dev)
/*
==============================================================================
Name: icp_multi_attach
Name: icp_multi_attach
Description:
This function sets up all the appropriate data for the current
device.
Description:
This function sets up all the appropriate data for the current
device.
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_devconfig *it Pointer to current device configuration
Parameters:
struct comedi_device *dev Pointer to current device structure
struct comedi_devconfig *it Pointer to current device configuration
Returns:int 0 = success
Returns:int 0 = success
==============================================================================
*/
@ -898,7 +913,8 @@ static int icp_multi_attach(struct comedi_device *dev,
resource_size_t io_addr[5], iobase;
unsigned char pci_bus, pci_slot, pci_func;
printk("icp_multi EDBG: BGN: icp_multi_attach(...)\n");
printk(KERN_WARNING
"icp_multi EDBG: BGN: icp_multi_attach(...)\n");
/* Alocate private data storage space */
ret = alloc_private(dev, sizeof(struct icp_multi_private));
@ -916,7 +932,8 @@ static int icp_multi_attach(struct comedi_device *dev,
);
}
printk("Anne's comedi%d: icp_multi: board=%s", dev->minor,
printk(KERN_WARNING
"Anne's comedi%d: icp_multi: board=%s", dev->minor,
this_board->name);
card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP,
@ -930,24 +947,26 @@ static int icp_multi_attach(struct comedi_device *dev,
if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0],
&irq)) < 0) {
printk(" - Can't get configuration data!\n");
printk(KERN_WARNING " - Can't get configuration data!\n");
return -EIO;
}
iobase = io_addr[2];
devpriv->phys_iobase = iobase;
printk(", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func,
printk(KERN_WARNING
", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func,
(unsigned long long)iobase);
devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE);
if (devpriv->io_addr == NULL) {
printk("ioremap failed.\n");
printk(KERN_WARNING "ioremap failed.\n");
return -ENOMEM;
}
#ifdef ICP_MULTI_EXTDEBUG
printk("0x%08llx mapped to %p, ", (unsigned long long)iobase,
printk(KERN_DEBUG
"0x%08llx mapped to %p, ", (unsigned long long)iobase,
devpriv->io_addr);
#endif
@ -975,20 +994,20 @@ static int icp_multi_attach(struct comedi_device *dev,
if (irq) {
if (request_irq(irq, interrupt_service_icp_multi,
IRQF_SHARED, "Inova Icp Multi", dev)) {
printk
(", unable to allocate IRQ %u, DISABLING IT",
printk(KERN_WARNING
"unable to allocate IRQ %u, DISABLING IT",
irq);
irq = 0; /* Can't use IRQ */
} else
printk(", irq=%u", irq);
printk(KERN_WARNING ", irq=%u", irq);
} else
printk(", IRQ disabled");
printk(KERN_WARNING ", IRQ disabled");
} else
irq = 0;
dev->irq = irq;
printk(".\n");
printk(KERN_WARNING ".\n");
subdev = 0;
@ -1063,7 +1082,7 @@ static int icp_multi_attach(struct comedi_device *dev,
devpriv->valid = 1;
#ifdef ICP_MULTI_EXTDEBUG
printk("icp multi EDBG: END: icp_multi_attach(...)\n");
printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_attach(...)\n");
#endif
return 0;
@ -1072,16 +1091,16 @@ static int icp_multi_attach(struct comedi_device *dev,
/*
==============================================================================
Name: icp_multi_detach
Name: icp_multi_detach
Description:
This function releases all the resources used by the current
device.
Description:
This function releases all the resources used by the current
device.
Parameters:
struct comedi_device *dev Pointer to current device structure
Parameters:
struct comedi_device *dev Pointer to current device structure
Returns:int 0 = success
Returns:int 0 = success
==============================================================================
*/

View File

@ -23,7 +23,8 @@
* no extern trigger implemented
*
* NOT WORKING (but soon) only 4 on-board differential channels supported
* NOT WORKING (but soon) only ONE di-port and ONE do-port supported instead of 4 digital ports
* NOT WORKING (but soon) only ONE di-port and ONE do-port supported
* instead of 4 digital ports
* di-port == Port 0
* do-port == Port 1
*
@ -63,17 +64,17 @@ the other carrier boards with small modifications. Modules supported
options for PCI-20006M:
first: Analog output channel 0 range configuration
0 bipolar 10 (-10V -- +10V)
1 unipolar 10 (0V -- +10V)
2 bipolar 5 (-5V -- 5V)
0 bipolar 10 (-10V -- +10V)
1 unipolar 10 (0V -- +10V)
2 bipolar 5 (-5V -- 5V)
second: Analog output channel 1 range configuration
options for PCI-20341M:
first: Analog input gain configuration
0 1
1 10
2 100
3 200
0 1
1 10
2 100
3 200
*/
/* XXX needs to use ioremap() for compatibility with 2.4 kernels. Should also
@ -95,12 +96,12 @@ options for PCI-20341M:
#define PCI20000_DIO_3 0xc1
#define PCI20000_DIO_CONTROL_01 0x83 /* port 0, 1 control */
#define PCI20000_DIO_CONTROL_23 0xc3 /* port 2, 3 control */
#define PCI20000_DIO_BUFFER 0x82 /* buffer direction and enable */
#define PCI20000_DIO_BUFFER 0x82 /* buffer direction & enable */
#define PCI20000_DIO_EOC 0xef /* even port, control output */
#define PCI20000_DIO_OOC 0xfd /* odd port, control output */
#define PCI20000_DIO_EIC 0x90 /* even port, control input */
#define PCI20000_DIO_OIC 0x82 /* odd port, control input */
#define DIO_CAND 0x12 /* and bit 1, bit 4 of control */
#define DIO_CAND 0x12 /* and bit 1 & 4 of control */
#define DIO_BE 0x01 /* buffer: port enable */
#define DIO_BO 0x04 /* buffer: output */
#define DIO_BI 0x05 /* buffer: input */
@ -137,7 +138,8 @@ union pci20xxx_subdev_private {
void *iobase;
struct {
void *iobase;
const struct comedi_lrange *ao_range_list[2]; /* range of channels of ao module */
const struct comedi_lrange *ao_range_list[2];
/* range of channels of ao module */
unsigned int last_data[2];
} pci20006;
struct {
@ -224,14 +226,13 @@ static int pci20xxx_attach(struct comedi_device *dev,
/* Check PCI-20001 C-2A Carrier Board ID */
if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
printk("comedi%d: ii_pci20kc", dev->minor);
printk
(" PCI-20001 C-2A Carrier Board at base=0x%p not found !\n",
devpriv->ioaddr);
printk(KERN_WARNING "comedi%d: ii_pci20kc PCI-20001"
" C-2A Carrier Board at base=0x%p not found !\n",
dev->minor, devpriv->ioaddr);
return -EINVAL;
}
printk("comedi%d:\n", dev->minor);
printk("ii_pci20kc: PCI-20001 C-2A at base=0x%p\n", devpriv->ioaddr);
printk(KERN_INFO "comedi%d: ii_pci20kc: PCI-20001 C-2A at base=0x%p\n",
dev->minor, devpriv->ioaddr);
for (i = 0; i < PCI20000_MODULES; i++) {
s = dev->subdevices + i;
@ -244,21 +245,23 @@ static int pci20xxx_attach(struct comedi_device *dev,
devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
pci20006_init(dev, s, it->options[2 * i + 2],
it->options[2 * i + 3]);
printk("comedi%d: ii_pci20kc", dev->minor);
printk(" PCI-20006 module in slot %d \n", i + 1);
printk(KERN_INFO "comedi%d: "
"ii_pci20kc PCI-20006 module in slot %d \n",
dev->minor, i + 1);
break;
case PCI20341_ID:
sdp->pci20341.iobase =
devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
pci20341_init(dev, s, it->options[2 * i + 2],
it->options[2 * i + 3]);
printk("comedi%d: ii_pci20kc", dev->minor);
printk(" PCI-20341 module in slot %d \n", i + 1);
printk(KERN_INFO "comedi%d: "
"ii_pci20kc PCI-20341 module in slot %d \n",
dev->minor, i + 1);
break;
default:
printk
("ii_pci20kc: unknown module code 0x%02x in slot %d: module disabled\n",
id, i);
printk(KERN_WARNING "ii_pci20kc: unknown module "
"code 0x%02x in slot %d: module disabled\n",
id, i); /* XXX this looks like a bug! i + 1 ?? */
/* fall through */
case PCI20xxx_EMPTY_ID:
s->type = COMEDI_SUBD_UNUSED;
@ -274,7 +277,7 @@ static int pci20xxx_attach(struct comedi_device *dev,
static int pci20xxx_detach(struct comedi_device *dev)
{
printk("comedi%d: pci20xxx: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor);
return 0;
}
@ -339,7 +342,8 @@ static int pci20006_insn_write(struct comedi_device *dev,
unsigned int boarddata;
sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0];
boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff); /* comedi-data -> board-data */
boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff);
/* comedi-data -> board-data */
lo = (boarddata & 0xff);
hi = ((boarddata >> 8) & 0xff);
@ -355,7 +359,8 @@ static int pci20006_insn_write(struct comedi_device *dev,
writeb(0x00, sdp->iobase + PCI20006_STROBE1);
break;
default:
printk(" comedi%d: pci20xxx: ao channel Error!\n", dev->minor);
printk(KERN_WARNING
" comedi%d: pci20xxx: ao channel Error!\n", dev->minor);
return -EINVAL;
}
@ -373,8 +378,7 @@ static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 };
static const struct comedi_lrange range_bipolar0_5 = { 1, {BIP_RANGE(0.5)} };
static const struct comedi_lrange range_bipolar0_05 = { 1, {BIP_RANGE(0.05)} };
static const struct comedi_lrange range_bipolar0_025 =
{ 1, {BIP_RANGE(0.025)} };
static const struct comedi_lrange range_bipolar0_025 = { 1, {BIP_RANGE(0.025)} };
static const struct comedi_lrange *const pci20341_ranges[] = {
&range_bipolar5,
@ -447,9 +451,10 @@ static int pci20341_insn_read(struct comedi_device *dev,
eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
}
if (j >= 100) {
printk
("comedi%d: pci20xxx: AI interrupt channel %i polling exit !\n",
dev->minor, i);
printk(KERN_WARNING
"comedi%d: pci20xxx: "
"AI interrupt channel %i polling exit !\n",
dev->minor, i);
return -EINVAL;
}
lo = readb(sdp->iobase + PCI20341_LDATA);
@ -502,20 +507,18 @@ static int pci20xxx_dio_insn_config(struct comedi_device *dev,
int mask, bits;
mask = 1 << CR_CHAN(insn->chanspec);
if (mask & 0x000000ff) {
if (mask & 0x000000ff)
bits = 0x000000ff;
} else if (mask & 0x0000ff00) {
else if (mask & 0x0000ff00)
bits = 0x0000ff00;
} else if (mask & 0x00ff0000) {
else if (mask & 0x00ff0000)
bits = 0x00ff0000;
} else {
else
bits = 0xff000000;
}
if (data[0]) {
if (data[0])
s->io_bits |= bits;
} else {
else
s->io_bits &= ~bits;
}
pci20xxx_dio_config(dev, s);
return 1;

View File

@ -192,12 +192,14 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
}
}
printk("comedi%d: no supported board found! (req. bus/slot: %d/%d)\n",
printk(KERN_WARNING
"comedi%d: no supported board found! (req. bus/slot: %d/%d)\n",
dev->minor, it->options[0], it->options[1]);
return -EIO;
found:
printk("comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor,
printk(KERN_INFO
"comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor,
board->name, pci_device->bus->number,
PCI_SLOT(pci_device->devfn));
devpriv->pcidev = pci_device;
@ -206,9 +208,9 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* enable PCI device and request regions */
error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME);
if (error < 0) {
printk
("comedi%d: failed to enable PCI device and request regions!\n",
dev->minor);
printk(KERN_WARNING "comedi%d: "
"failed to enable PCI device and request regions!\n",
dev->minor);
return error;
}
@ -239,7 +241,8 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outb(0, dev->iobase + 0x20);
outb(0, dev->iobase + 0x40);
printk("comedi%d: " CNT_DRIVER_NAME " attached.\n", dev->minor);
printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n",
dev->minor);
return 0;
}
@ -248,11 +251,11 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static int cnt_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->pcidev) {
if (dev->iobase) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
}
pci_dev_put(devpriv->pcidev);
}
printk("comedi%d: " CNT_DRIVER_NAME " remove\n", dev->minor);
printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
dev->minor);
return 0;
}

View File

@ -840,7 +840,7 @@ static int xilinx_download(struct comedi_device *dev)
"comedi%d: me4000: xilinx_download(): DONE flag is not set\n",
dev->minor);
printk(KERN_ERR
"comedi%d: me4000: xilinx_download(): Download not succesful\n",
"comedi%d: me4000: xilinx_download(): Download not successful\n",
dev->minor);
return -EIO;
}

View File

@ -64,6 +64,7 @@
MODULE_LICENSE("GPL");
struct mite_struct *mite_devices;
EXPORT_SYMBOL(mite_devices);
#define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK)))
@ -80,7 +81,7 @@ void mite_init(void)
mite = kzalloc(sizeof(*mite), GFP_KERNEL);
if (!mite) {
printk("mite: allocation failed\n");
printk(KERN_ERR "mite: allocation failed\n");
pci_dev_put(pcidev);
return;
}
@ -99,14 +100,14 @@ void mite_init(void)
static void dump_chip_signature(u32 csigr_bits)
{
printk
("mite: version = %i, type = %i, mite mode = %i, interface mode = %i\n",
mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits),
mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits));
printk
("mite: num channels = %i, write post fifo depth = %i, wins = %i, iowins = %i\n",
mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits),
mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits));
printk(KERN_INFO "mite: version = %i, type = %i, mite mode = %i,"
"interface mode = %i\n",
mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits),
mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits));
printk(KERN_INFO "mite: num channels = %i, write post fifo depth = %i,"
"wins = %i, iowins = %i\n",
mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits),
mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits));
}
unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel)
@ -126,7 +127,7 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
unsigned unknown_dma_burst_bits;
if (comedi_pci_enable(mite->pcidev, "mite")) {
printk("error enabling mite and requesting io regions\n");
printk(KERN_ERR "error enabling mite and requesting io regions\n");
return -EIO;
}
pci_set_master(mite->pcidev);
@ -135,27 +136,30 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
mite->mite_phys_addr = addr;
mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE);
if (!mite->mite_io_addr) {
printk("failed to remap mite io memory address\n");
printk(KERN_ERR "Failed to remap mite io memory address\n");
return -ENOMEM;
}
printk("MITE:0x%08llx mapped to %p ",
printk(KERN_INFO "MITE:0x%08llx mapped to %p ",
(unsigned long long)mite->mite_phys_addr, mite->mite_io_addr);
addr = pci_resource_start(mite->pcidev, 1);
mite->daq_phys_addr = addr;
length = pci_resource_len(mite->pcidev, 1);
/* In case of a 660x board, DAQ size is 8k instead of 4k (see as shown by lspci output) */
/*
* In case of a 660x board, DAQ size is 8k instead of 4k
* (see as shown by lspci output)
*/
mite->daq_io_addr = ioremap(mite->daq_phys_addr, length);
if (!mite->daq_io_addr) {
printk("failed to remap daq io memory address\n");
printk(KERN_ERR "Failed to remap daq io memory address\n");
return -ENOMEM;
}
printk("DAQ:0x%08llx mapped to %p\n",
printk(KERN_INFO "DAQ:0x%08llx mapped to %p\n",
(unsigned long long)mite->daq_phys_addr, mite->daq_io_addr);
if (use_iodwbsr_1) {
writel(0, mite->mite_io_addr + MITE_IODWBSR);
printk("mite: using I/O Window Base Size register 1\n");
printk(KERN_INFO "mite: using I/O Window Base Size register 1\n");
writel(mite->daq_phys_addr | WENAB |
MITE_IODWBSR_1_WSIZE_bits(length),
mite->mite_io_addr + MITE_IODWBSR_1);
@ -164,11 +168,12 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
writel(mite->daq_phys_addr | WENAB,
mite->mite_io_addr + MITE_IODWBSR);
}
/* make sure dma bursts work. I got this from running a bus analyzer
on a pxi-6281 and a pxi-6713. 6713 powered up with register value
of 0x61f and bursts worked. 6281 powered up with register value of
0x1f and bursts didn't work. The NI windows driver reads the register,
then does a bitwise-or of 0x600 with it and writes it back.
/*
* make sure dma bursts work. I got this from running a bus analyzer
* on a pxi-6281 and a pxi-6713. 6713 powered up with register value
* of 0x61f and bursts worked. 6281 powered up with register value of
* 0x1f and bursts didn't work. The NI windows driver reads the
* register, then does a bitwise-or of 0x600 with it and writes it back.
*/
unknown_dma_burst_bits =
readl(mite->mite_io_addr + MITE_UNKNOWN_DMA_BURST_REG);
@ -179,9 +184,9 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
csigr_bits = readl(mite->mite_io_addr + MITE_CSIGR);
mite->num_channels = mite_csigr_dmac(csigr_bits);
if (mite->num_channels > MAX_MITE_DMA_CHANNELS) {
printk
("mite: bug? chip claims to have %i dma channels. Setting to %i.\n",
mite->num_channels, MAX_MITE_DMA_CHANNELS);
printk(KERN_WARNING "mite: bug? chip claims to have %i dma "
"channels. Setting to %i.\n",
mite->num_channels, MAX_MITE_DMA_CHANNELS);
mite->num_channels = MAX_MITE_DMA_CHANNELS;
}
dump_chip_signature(csigr_bits);
@ -194,16 +199,18 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
mite->mite_io_addr + MITE_CHCR(i));
}
mite->fifo_size = mite_fifo_size(mite, 0);
printk("mite: fifo size is %i.\n", mite->fifo_size);
printk(KERN_INFO "mite: fifo size is %i.\n", mite->fifo_size);
mite->used = 1;
return 0;
}
EXPORT_SYMBOL(mite_setup2);
int mite_setup(struct mite_struct *mite)
{
return mite_setup2(mite, 0);
}
EXPORT_SYMBOL(mite_setup);
void mite_cleanup(void)
{
@ -238,22 +245,23 @@ void mite_unsetup(struct mite_struct *mite)
mite->used = 0;
}
EXPORT_SYMBOL(mite_unsetup);
void mite_list_devices(void)
{
struct mite_struct *mite, *next;
printk("Available NI device IDs:");
printk(KERN_INFO "Available NI device IDs:");
if (mite_devices)
for (mite = mite_devices; mite; mite = next) {
next = mite->next;
printk(" 0x%04x", mite_device_id(mite));
printk(KERN_INFO " 0x%04x", mite_device_id(mite));
if (mite->used)
printk("(used)");
printk(KERN_INFO "(used)");
}
printk("\n");
printk(KERN_INFO "\n");
}
EXPORT_SYMBOL(mite_list_devices);
struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
struct
@ -265,7 +273,9 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
unsigned long flags;
struct mite_channel *channel = NULL;
/* spin lock so mite_release_channel can be called safely from interrupts */
/* spin lock so mite_release_channel can be called safely
* from interrupts
*/
spin_lock_irqsave(&mite->lock, flags);
for (i = min_channel; i <= max_channel; ++i) {
if (mite->channel_allocated[i] == 0) {
@ -278,6 +288,7 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
spin_unlock_irqrestore(&mite->lock, flags);
return channel;
}
EXPORT_SYMBOL(mite_request_channel_in_range);
void mite_release_channel(struct mite_channel *mite_chan)
{
@ -289,8 +300,10 @@ void mite_release_channel(struct mite_channel *mite_chan)
if (mite->channel_allocated[mite_chan->channel]) {
mite_dma_disarm(mite_chan);
mite_dma_reset(mite_chan);
/* disable all channel's interrupts (do it after disarm/reset so
MITE_CHCR reg isn't changed while dma is still active!) */
/*
* disable all channel's interrupts (do it after disarm/reset so
* MITE_CHCR reg isn't changed while dma is still active!)
*/
writel(CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE |
CHCR_CLR_SAR_IE | CHCR_CLR_DONE_IE |
CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE |
@ -302,6 +315,7 @@ MITE_CHCR reg isn't changed while dma is still active!) */
}
spin_unlock_irqrestore(&mite->lock, flags);
}
EXPORT_SYMBOL(mite_release_channel);
void mite_dma_arm(struct mite_channel *mite_chan)
{
@ -310,8 +324,10 @@ void mite_dma_arm(struct mite_channel *mite_chan)
unsigned long flags;
MDPRINTK("mite_dma_arm ch%i\n", channel);
/* memory barrier is intended to insure any twiddling with the buffer
is done before writing to the mite to arm dma transfer */
/*
* memory barrier is intended to insure any twiddling with the buffer
* is done before writing to the mite to arm dma transfer
*/
smp_mb();
/* arm */
chor = CHOR_START;
@ -322,6 +338,7 @@ void mite_dma_arm(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
/* mite_dma_tcr(mite, channel); */
}
EXPORT_SYMBOL(mite_dma_arm);
/**************************************/
@ -354,7 +371,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
n_links * sizeof(struct mite_dma_descriptor),
&ring->descriptors_dma_addr, GFP_KERNEL);
if (!ring->descriptors) {
printk("mite: ring buffer allocation failed\n");
printk(KERN_ERR "mite: ring buffer allocation failed\n");
return -ENOMEM;
}
ring->n_links = n_links;
@ -370,11 +387,14 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
}
ring->descriptors[n_links - 1].next =
cpu_to_le32(ring->descriptors_dma_addr);
/* barrier is meant to insure that all the writes to the dma descriptors
have completed before the dma controller is commanded to read them */
/*
* barrier is meant to insure that all the writes to the dma descriptors
* have completed before the dma controller is commanded to read them
*/
smp_wmb();
return 0;
}
EXPORT_SYMBOL(mite_buf_change);
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits)
@ -395,16 +415,19 @@ void mite_prep_dma(struct mite_channel *mite_chan,
* Link Complete Interrupt: interrupt every time a link
* in MITE_RING is completed. This can generate a lot of
* extra interrupts, but right now we update the values
* of buf_int_ptr and buf_int_count at each interrupt. A
* of buf_int_ptr and buf_int_count at each interrupt. A
* better method is to poll the MITE before each user
* "read()" to calculate the number of bytes available.
*/
chcr |= CHCR_SET_LC_IE;
if (num_memory_bits == 32 && num_device_bits == 16) {
/* Doing a combined 32 and 16 bit byteswap gets the 16 bit samples into the fifo in the right order.
Tested doing 32 bit memory to 16 bit device transfers to the analog out of a pxi-6281,
which has mite version = 1, type = 4. This also works for dma reads from the counters
on e-series boards. */
/*
* Doing a combined 32 and 16 bit byteswap gets the 16 bit
* samples into the fifo in the right order. Tested doing 32 bit
* memory to 16 bit device transfers to the analog out of a
* pxi-6281, which has mite version = 1, type = 4. This also
* works for dma reads from the counters on e-series boards.
*/
chcr |= CHCR_BYTE_SWAP_DEVICE | CHCR_BYTE_SWAP_MEMORY;
}
if (mite_chan->dir == COMEDI_INPUT)
@ -425,7 +448,8 @@ void mite_prep_dma(struct mite_channel *mite_chan,
mcr |= CR_PSIZE32;
break;
default:
printk("mite: bug! invalid mem bit width for dma transfer\n");
printk(KERN_WARNING "mite: bug! invalid mem bit width for dma "
"transfer\n");
break;
}
writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel));
@ -444,7 +468,8 @@ void mite_prep_dma(struct mite_channel *mite_chan,
dcr |= CR_PSIZE32;
break;
default:
printk("mite: bug! invalid dev bit width for dma transfer\n");
printk(KERN_WARNING "mite: bug! invalid dev bit width for dma "
"transfer\n");
break;
}
writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel));
@ -462,6 +487,7 @@ void mite_prep_dma(struct mite_channel *mite_chan,
MDPRINTK("exit mite_prep_dma\n");
}
EXPORT_SYMBOL(mite_prep_dma);
u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
{
@ -469,48 +495,53 @@ u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel));
}
u32 mite_bytes_in_transit(struct mite_channel * mite_chan)
u32 mite_bytes_in_transit(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
return readl(mite->mite_io_addr +
MITE_FCR(mite_chan->channel)) & 0x000000FF;
}
EXPORT_SYMBOL(mite_bytes_in_transit);
/* returns lower bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_lb(struct mite_channel * mite_chan)
/* returns lower bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan)
{
u32 device_byte_count;
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count - mite_bytes_in_transit(mite_chan);
}
EXPORT_SYMBOL(mite_bytes_written_to_memory_lb);
/* returns upper bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_ub(struct mite_channel * mite_chan)
/* returns upper bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan)
{
u32 in_transit_count;
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) - in_transit_count;
}
EXPORT_SYMBOL(mite_bytes_written_to_memory_ub);
/* returns lower bound for number of bytes read from memory for transfer to device */
u32 mite_bytes_read_from_memory_lb(struct mite_channel * mite_chan)
/* returns lower bound for number of bytes read from memory to device */
u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan)
{
u32 device_byte_count;
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count + mite_bytes_in_transit(mite_chan);
}
EXPORT_SYMBOL(mite_bytes_read_from_memory_lb);
/* returns upper bound for number of bytes read from memory for transfer to device */
u32 mite_bytes_read_from_memory_ub(struct mite_channel * mite_chan)
/* returns upper bound for number of bytes read from memory to device */
u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan)
{
u32 in_transit_count;
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) + in_transit_count;
}
EXPORT_SYMBOL(mite_bytes_read_from_memory_ub);
unsigned mite_dma_tcr(struct mite_channel *mite_chan)
{
@ -525,6 +556,7 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan)
return tcr;
}
EXPORT_SYMBOL(mite_dma_tcr);
void mite_dma_disarm(struct mite_channel *mite_chan)
{
@ -535,6 +567,7 @@ void mite_dma_disarm(struct mite_channel *mite_chan)
chor = CHOR_ABORT;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
}
EXPORT_SYMBOL(mite_dma_disarm);
int mite_sync_input_dma(struct mite_channel *mite_chan,
struct comedi_async *async)
@ -544,7 +577,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice);
old_alloc_count = async->buf_write_alloc_count;
/* write alloc as much as we can */
/* write alloc as much as we can */
comedi_buf_write_alloc(async, async->prealloc_bufsz);
nbytes = mite_bytes_written_to_memory_lb(mite_chan);
@ -571,6 +604,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
async->events |= COMEDI_CB_BLOCK;
return 0;
}
EXPORT_SYMBOL(mite_sync_input_dma);
int mite_sync_output_dma(struct mite_channel *mite_chan,
struct comedi_async *async)
@ -593,7 +627,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
(int)(nbytes_ub - stop_count) > 0)
nbytes_ub = stop_count;
if ((int)(nbytes_ub - old_alloc_count) > 0) {
printk("mite: DMA underrun\n");
printk(KERN_ERR "mite: DMA underrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
}
@ -607,6 +641,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
}
return 0;
}
EXPORT_SYMBOL(mite_sync_output_dma);
unsigned mite_get_status(struct mite_channel *mite_chan)
{
@ -625,6 +660,7 @@ unsigned mite_get_status(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
return status;
}
EXPORT_SYMBOL(mite_get_status);
int mite_done(struct mite_channel *mite_chan)
{
@ -638,6 +674,7 @@ int mite_done(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
return done;
}
EXPORT_SYMBOL(mite_done);
#ifdef DEBUG_MITE
@ -719,46 +756,51 @@ void mite_dump_regs(struct mite_channel *mite_chan)
unsigned long addr = 0;
unsigned long temp = 0;
printk("mite_dump_regs ch%i\n", mite_chan->channel);
printk("mite address is =0x%08lx\n", mite_io_addr);
printk(KERN_DEBUG "mite_dump_regs ch%i\n", mite_chan->channel);
printk(KERN_DEBUG "mite address is =0x%08lx\n", mite_io_addr);
addr = mite_io_addr + MITE_CHOR(channel);
printk("mite status[CHOR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
printk(KERN_DEBUG "mite status[CHOR]at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_CHOR_strings, temp);
addr = mite_io_addr + MITE_CHCR(channel);
printk("mite status[CHCR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
printk(KERN_DEBUG "mite status[CHCR]at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_CHCR_strings, temp);
addr = mite_io_addr + MITE_TCR(channel);
printk("mite status[TCR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_MCR(channel);
printk("mite status[MCR] at 0x%08lx =0x%08lx\n", addr, temp =
printk(KERN_DEBUG "mite status[TCR] at 0x%08lx =0x%08x\n", addr,
readl(addr));
addr = mite_io_addr + MITE_MCR(channel);
printk(KERN_DEBUG "mite status[MCR] at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_MCR_strings, temp);
addr = mite_io_addr + MITE_MAR(channel);
printk("mite status[MAR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_DCR(channel);
printk("mite status[DCR] at 0x%08lx =0x%08lx\n", addr, temp =
printk(KERN_DEBUG "mite status[MAR] at 0x%08lx =0x%08x\n", addr,
readl(addr));
addr = mite_io_addr + MITE_DCR(channel);
printk(KERN_DEBUG "mite status[DCR] at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_DCR_strings, temp);
addr = mite_io_addr + MITE_DAR(channel);
printk("mite status[DAR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_LKCR(channel);
printk("mite status[LKCR]at 0x%08lx =0x%08lx\n", addr, temp =
printk(KERN_DEBUG "mite status[DAR] at 0x%08lx =0x%08x\n", addr,
readl(addr));
addr = mite_io_addr + MITE_LKCR(channel);
printk(KERN_DEBUG "mite status[LKCR]at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_LKCR_strings, temp);
addr = mite_io_addr + MITE_LKAR(channel);
printk("mite status[LKAR]at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_CHSR(channel);
printk("mite status[CHSR]at 0x%08lx =0x%08lx\n", addr, temp =
printk(KERN_DEBUG "mite status[LKAR]at 0x%08lx =0x%08x\n", addr,
readl(addr));
addr = mite_io_addr + MITE_CHSR(channel);
printk(KERN_DEBUG "mite status[CHSR]at 0x%08lx =0x%08lx\n", addr,
temp = readl(addr));
mite_decode(mite_CHSR_strings, temp);
addr = mite_io_addr + MITE_FCR(channel);
printk("mite status[FCR] at 0x%08lx =0x%08x\n\n", addr, readl(addr));
printk(KERN_DEBUG "mite status[FCR] at 0x%08lx =0x%08x\n\n", addr,
readl(addr));
}
EXPORT_SYMBOL(mite_dump_regs);
static void mite_decode(char **bit_str, unsigned int bits)
{
@ -766,10 +808,11 @@ static void mite_decode(char **bit_str, unsigned int bits)
for (i = 31; i >= 0; i--) {
if (bits & (1 << i))
printk(" %s", bit_str[i]);
printk(KERN_DEBUG " %s", bit_str[i]);
}
printk("\n");
printk(KERN_DEBUG "\n");
}
EXPORT_SYMBOL(mite_decode);
#endif
#ifdef MODULE
@ -785,36 +828,4 @@ void __exit cleanup_module(void)
{
mite_cleanup();
}
EXPORT_SYMBOL(mite_dma_tcr);
EXPORT_SYMBOL(mite_dma_arm);
EXPORT_SYMBOL(mite_dma_disarm);
EXPORT_SYMBOL(mite_sync_input_dma);
EXPORT_SYMBOL(mite_sync_output_dma);
EXPORT_SYMBOL(mite_setup);
EXPORT_SYMBOL(mite_setup2);
EXPORT_SYMBOL(mite_unsetup);
#if 0
EXPORT_SYMBOL(mite_kvmem_segment_load);
EXPORT_SYMBOL(mite_ll_from_kvmem);
EXPORT_SYMBOL(mite_setregs);
#endif
EXPORT_SYMBOL(mite_devices);
EXPORT_SYMBOL(mite_list_devices);
EXPORT_SYMBOL(mite_request_channel_in_range);
EXPORT_SYMBOL(mite_release_channel);
EXPORT_SYMBOL(mite_prep_dma);
EXPORT_SYMBOL(mite_buf_change);
EXPORT_SYMBOL(mite_bytes_written_to_memory_lb);
EXPORT_SYMBOL(mite_bytes_written_to_memory_ub);
EXPORT_SYMBOL(mite_bytes_read_from_memory_lb);
EXPORT_SYMBOL(mite_bytes_read_from_memory_ub);
EXPORT_SYMBOL(mite_bytes_in_transit);
EXPORT_SYMBOL(mite_get_status);
EXPORT_SYMBOL(mite_done);
#ifdef DEBUG_MITE
EXPORT_SYMBOL(mite_decode);
EXPORT_SYMBOL(mite_dump_regs);
#endif
#endif

View File

@ -163,13 +163,6 @@ u32 mite_bytes_in_transit(struct mite_channel *mite_chan);
unsigned mite_get_status(struct mite_channel *mite_chan);
int mite_done(struct mite_channel *mite_chan);
#if 0
unsigned long mite_ll_from_kvmem(struct mite_struct *mite,
struct comedi_async *async, int len);
void mite_setregs(struct mite_struct *mite, unsigned long ll_start, int chan,
int dir);
#endif
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits);
int mite_buf_change(struct mite_dma_descriptor_ring *ring,

View File

@ -144,9 +144,8 @@ static int multiq3_ao_insn_read(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
}
return i;
}
@ -253,20 +252,20 @@ static int multiq3_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
iobase = it->options[0];
printk("comedi%d: multiq3: 0x%04lx ", dev->minor, iobase);
printk(KERN_INFO "comedi%d: multiq3: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, MULTIQ3_SIZE, "multiq3")) {
printk("comedi%d: I/O port conflict\n", dev->minor);
printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
return -EIO;
}
dev->iobase = iobase;
irq = it->options[1];
if (irq) {
printk("comedi%d: irq = %u ignored\n", dev->minor, irq);
} else {
printk("comedi%d: no irq\n", dev->minor);
}
if (irq)
printk(KERN_WARNING "comedi%d: irq = %u ignored\n",
dev->minor, irq);
else
printk(KERN_WARNING "comedi%d: no irq\n", dev->minor);
dev->board_name = "multiq3";
result = alloc_subdevices(dev, 5);
if (result < 0)
@ -330,14 +329,12 @@ static int multiq3_attach(struct comedi_device *dev,
static int multiq3_detach(struct comedi_device *dev)
{
printk("comedi%d: multiq3: remove\n", dev->minor);
printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor);
if (dev->iobase) {
if (dev->iobase)
release_region(dev->iobase, MULTIQ3_SIZE);
}
if (dev->irq) {
if (dev->irq)
free_irq(dev->irq, dev);
}
return 0;
}

View File

@ -273,7 +273,8 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev,
if (err)
return 1;
/* step 2: make sure trigger sources are unique and mutually compatible */
/* step 2: make sure trigger sources are unique and */
/* are mutually compatible */
if (err)
return 2;
@ -377,7 +378,7 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
printk("comedi%d: ni6527:", dev->minor);
printk(KERN_INFO "comedi%d: ni6527\n", dev->minor);
ret = alloc_private(dev, sizeof(struct ni6527_private));
if (ret < 0)
@ -389,14 +390,13 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = mite_setup(devpriv->mite);
if (ret < 0) {
printk("error setting up mite\n");
printk(KERN_ERR "comedi: error setting up mite\n");
return ret;
}
dev->board_name = this_board->name;
printk(" %s", dev->board_name);
printk(" ID=0x%02x", readb(devpriv->mite->daq_io_addr + ID_Register));
printk(KERN_INFO "comedi board: %s, ID=0x%02x\n", dev->board_name,
readb(devpriv->mite->daq_io_addr + ID_Register));
ret = alloc_subdevices(dev, 3);
if (ret < 0)
@ -415,7 +415,7 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
s->n_chan = 24;
s->range_table = &range_unknown; /* FIXME: actually conductance */
s->range_table = &range_unknown; /* FIXME: actually conductance */
s->maxdata = 1;
s->insn_bits = ni6527_do_insn_bits;
@ -442,30 +442,25 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt,
IRQF_SHARED, "ni6527", dev);
if (ret < 0) {
printk(" irq not available");
} else
if (ret < 0)
printk(KERN_WARNING "comedi i6527 irq not available\n");
else
dev->irq = mite_irq(devpriv->mite);
printk("\n");
return 0;
}
static int ni6527_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) {
if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
writeb(0x00,
devpriv->mite->daq_io_addr + Master_Interrupt_Control);
}
if (dev->irq) {
if (dev->irq)
free_irq(dev->irq, dev);
}
if (devpriv && devpriv->mite) {
if (devpriv && devpriv->mite)
mite_unsetup(devpriv->mite);
}
return 0;
}
@ -491,7 +486,7 @@ static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
printk("no device found\n");
printk(KERN_ERR "comedi 6527: no device found\n");
mite_list_devices();
return -EIO;
}

View File

@ -32,7 +32,8 @@ Configuration options:
[0] - I/O port base address
[1] - IRQ (unused)
[2] - DMA (unused)
[3] - analog output range, set by jumpers on hardware (0 for -10 to 10V bipolar, 1 for 0V to 10V unipolar)
[3] - analog output range, set by jumpers on hardware (0 for -10 to 10V
bipolar, 1 for 0V to 10V unipolar)
*/
/*
@ -431,9 +432,8 @@ static int atao_calib_insn_read(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
int i;
for (i = 0; i < insn->n; i++) {
for (i = 0; i < insn->n; i++)
data[i] = 0; /* XXX */
}
return insn->n;
}

Some files were not shown because too many files have changed in this diff Show More