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:
Коммит
0e2f7b8376
|
@ -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"
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
||||
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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");
|
||||
|
|
@ -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);
|
||||
|
|
@ -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");
|
|
@ -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
|
|
@ -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");
|
|
@ -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
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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) */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
@ -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));
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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[]);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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[];
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 (;;) {
|
||||
/*******************/
|
||||
|
|
|
@ -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->
|
||||
|
|
|
@ -1808,7 +1808,7 @@ int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device
|
|||
2) {
|
||||
if (dw_Status & 4) {
|
||||
/************************/
|
||||
/* Tor counter owerflow */
|
||||
/* Tor counter overflow */
|
||||
/************************/
|
||||
|
||||
*pb_TorCounterStatus
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>");
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 @@ conv_finish:
|
|||
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 @@ conv_finish:
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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 @@ dac_ready:
|
|||
}
|
||||
|
||||
#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 @@ dac_ready:
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
|
|
@ -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 @@ Options:
|
|||
|
||||
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;
|
||||
|
|
|
@ -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 @@ found:
|
|||
/* 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 @@ found:
|
|||
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 @@ found:
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче