mirror of https://gitee.com/openkylin/linux.git
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/w1-2.6
This commit is contained in:
commit
6d8de3a26b
|
@ -54,4 +54,20 @@ config W1_SMEM
|
||||||
Say Y here if you want to connect 1-wire
|
Say Y here if you want to connect 1-wire
|
||||||
simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
|
simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
|
||||||
|
|
||||||
|
config W1_DS2433
|
||||||
|
tristate "4kb EEPROM family support (DS2433)"
|
||||||
|
depends on W1
|
||||||
|
help
|
||||||
|
Say Y here if you want to use a 1-wire
|
||||||
|
4kb EEPROM family device (DS2433).
|
||||||
|
|
||||||
|
config W1_DS2433_CRC
|
||||||
|
bool "Protect DS2433 data with a CRC16"
|
||||||
|
depends on W1_DS2433
|
||||||
|
select CRC16
|
||||||
|
help
|
||||||
|
Say Y here to protect DS2433 data with a CRC16.
|
||||||
|
Each block has 30 bytes of data and a two byte CRC16.
|
||||||
|
Full block writes are only allowed if the CRC is valid.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -6,6 +6,10 @@ ifneq ($(CONFIG_NET), y)
|
||||||
EXTRA_CFLAGS += -DNETLINK_DISABLED
|
EXTRA_CFLAGS += -DNETLINK_DISABLED
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_W1_DS2433_CRC), y)
|
||||||
|
EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC
|
||||||
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_W1) += wire.o
|
obj-$(CONFIG_W1) += wire.o
|
||||||
wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
|
wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
|
||||||
|
|
||||||
|
@ -13,8 +17,9 @@ obj-$(CONFIG_W1_MATROX) += matrox_w1.o
|
||||||
obj-$(CONFIG_W1_THERM) += w1_therm.o
|
obj-$(CONFIG_W1_THERM) += w1_therm.o
|
||||||
obj-$(CONFIG_W1_SMEM) += w1_smem.o
|
obj-$(CONFIG_W1_SMEM) += w1_smem.o
|
||||||
|
|
||||||
obj-$(CONFIG_W1_DS9490) += ds9490r.o
|
obj-$(CONFIG_W1_DS9490) += ds9490r.o
|
||||||
ds9490r-objs := dscore.o
|
ds9490r-objs := dscore.o
|
||||||
|
|
||||||
obj-$(CONFIG_W1_DS9490_BRIDGE) += ds_w1_bridge.o
|
obj-$(CONFIG_W1_DS9490_BRIDGE) += ds_w1_bridge.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_W1_DS2433) += w1_ds2433.o
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* ds_w1_bridge.c
|
* ds_w1_bridge.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
#include "../w1/w1.h"
|
#include "../w1/w1.h"
|
||||||
#include "../w1/w1_int.h"
|
#include "../w1/w1_int.h"
|
||||||
#include "dscore.h"
|
#include "dscore.h"
|
||||||
|
|
||||||
static struct ds_device *ds_dev;
|
static struct ds_device *ds_dev;
|
||||||
static struct w1_bus_master *ds_bus_master;
|
static struct w1_bus_master *ds_bus_master;
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ static u8 ds9490r_reset(unsigned long data)
|
||||||
static int __devinit ds_w1_init(void)
|
static int __devinit ds_w1_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
|
ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
|
||||||
if (!ds_bus_master) {
|
if (!ds_bus_master) {
|
||||||
printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
|
printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
|
||||||
|
@ -136,14 +136,14 @@ static int __devinit ds_w1_init(void)
|
||||||
|
|
||||||
memset(ds_bus_master, 0, sizeof(*ds_bus_master));
|
memset(ds_bus_master, 0, sizeof(*ds_bus_master));
|
||||||
|
|
||||||
ds_bus_master->data = (unsigned long)ds_dev;
|
ds_bus_master->data = (unsigned long)ds_dev;
|
||||||
ds_bus_master->touch_bit = &ds9490r_touch_bit;
|
ds_bus_master->touch_bit = &ds9490r_touch_bit;
|
||||||
ds_bus_master->read_bit = &ds9490r_read_bit;
|
ds_bus_master->read_bit = &ds9490r_read_bit;
|
||||||
ds_bus_master->write_bit = &ds9490r_write_bit;
|
ds_bus_master->write_bit = &ds9490r_write_bit;
|
||||||
ds_bus_master->read_byte = &ds9490r_read_byte;
|
ds_bus_master->read_byte = &ds9490r_read_byte;
|
||||||
ds_bus_master->write_byte = &ds9490r_write_byte;
|
ds_bus_master->write_byte = &ds9490r_write_byte;
|
||||||
ds_bus_master->read_block = &ds9490r_read_block;
|
ds_bus_master->read_block = &ds9490r_read_block;
|
||||||
ds_bus_master->write_block = &ds9490r_write_block;
|
ds_bus_master->write_block = &ds9490r_write_block;
|
||||||
ds_bus_master->reset_bus = &ds9490r_reset;
|
ds_bus_master->reset_bus = &ds9490r_reset;
|
||||||
|
|
||||||
err = w1_add_master_device(ds_bus_master);
|
err = w1_add_master_device(ds_bus_master);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* dscore.c
|
* dscore.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,19 +32,16 @@ static struct usb_device_id ds_id_table [] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, ds_id_table);
|
MODULE_DEVICE_TABLE(usb, ds_id_table);
|
||||||
|
|
||||||
int ds_probe(struct usb_interface *, const struct usb_device_id *);
|
static int ds_probe(struct usb_interface *, const struct usb_device_id *);
|
||||||
void ds_disconnect(struct usb_interface *);
|
static void ds_disconnect(struct usb_interface *);
|
||||||
|
|
||||||
int ds_touch_bit(struct ds_device *, u8, u8 *);
|
int ds_touch_bit(struct ds_device *, u8, u8 *);
|
||||||
int ds_read_byte(struct ds_device *, u8 *);
|
int ds_read_byte(struct ds_device *, u8 *);
|
||||||
int ds_read_bit(struct ds_device *, u8 *);
|
int ds_read_bit(struct ds_device *, u8 *);
|
||||||
int ds_write_byte(struct ds_device *, u8);
|
int ds_write_byte(struct ds_device *, u8);
|
||||||
int ds_write_bit(struct ds_device *, u8);
|
int ds_write_bit(struct ds_device *, u8);
|
||||||
int ds_start_pulse(struct ds_device *, int);
|
static int ds_start_pulse(struct ds_device *, int);
|
||||||
int ds_set_speed(struct ds_device *, int);
|
|
||||||
int ds_reset(struct ds_device *, struct ds_status *);
|
int ds_reset(struct ds_device *, struct ds_status *);
|
||||||
int ds_detect(struct ds_device *, struct ds_status *);
|
|
||||||
int ds_stop_pulse(struct ds_device *, int);
|
|
||||||
struct ds_device * ds_get_device(void);
|
struct ds_device * ds_get_device(void);
|
||||||
void ds_put_device(struct ds_device *);
|
void ds_put_device(struct ds_device *);
|
||||||
|
|
||||||
|
@ -79,11 +76,11 @@ void ds_put_device(struct ds_device *dev)
|
||||||
static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
|
static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
||||||
CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
|
CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
|
printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
|
||||||
value, index, err);
|
value, index, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -94,11 +91,11 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
|
||||||
static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
|
static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
||||||
MODE_CMD, 0x40, value, index, NULL, 0, 1000);
|
MODE_CMD, 0x40, value, index, NULL, 0, 1000);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
|
printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
|
||||||
value, index, err);
|
value, index, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -109,11 +106,11 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
|
||||||
static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
|
static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
|
||||||
COMM_CMD, 0x40, value, index, NULL, 0, 1000);
|
COMM_CMD, 0x40, value, index, NULL, 0, 1000);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
|
printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
|
||||||
value, index, err);
|
value, index, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -126,19 +123,20 @@ static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int of
|
||||||
printk("%45s: %8x\n", str, buf[off]);
|
printk("%45s: %8x\n", str, buf[off]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, unsigned char *buf, int size)
|
static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
|
||||||
|
unsigned char *buf, int size)
|
||||||
{
|
{
|
||||||
int count, err;
|
int count, err;
|
||||||
|
|
||||||
memset(st, 0, sizeof(st));
|
memset(st, 0, sizeof(st));
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
|
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
|
printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count >= sizeof(*st))
|
if (count >= sizeof(*st))
|
||||||
memcpy(st, buf, sizeof(*st));
|
memcpy(st, buf, sizeof(*st));
|
||||||
|
|
||||||
|
@ -149,13 +147,13 @@ static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
|
||||||
{
|
{
|
||||||
unsigned char buf[64];
|
unsigned char buf[64];
|
||||||
int count, err = 0, i;
|
int count, err = 0, i;
|
||||||
|
|
||||||
memcpy(st, buf, sizeof(*st));
|
memcpy(st, buf, sizeof(*st));
|
||||||
|
|
||||||
count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
|
count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
|
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
|
||||||
for (i=0; i<count; ++i)
|
for (i=0; i<count; ++i)
|
||||||
printk("%02x ", buf[i]);
|
printk("%02x ", buf[i]);
|
||||||
|
@ -199,7 +197,7 @@ static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +205,9 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
|
||||||
{
|
{
|
||||||
int count, err;
|
int count, err;
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
|
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
|
||||||
buf, size, &count, 1000);
|
buf, size, &count, 1000);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
|
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
|
||||||
|
@ -234,7 +232,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
|
||||||
static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
|
static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
int count, err;
|
int count, err;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
|
err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -245,12 +243,14 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
int ds_stop_pulse(struct ds_device *dev, int limit)
|
int ds_stop_pulse(struct ds_device *dev, int limit)
|
||||||
{
|
{
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
int count = 0, err = 0;
|
int count = 0, err = 0;
|
||||||
u8 buf[0x20];
|
u8 buf[0x20];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
|
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -275,7 +275,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
|
||||||
int ds_detect(struct ds_device *dev, struct ds_status *st)
|
int ds_detect(struct ds_device *dev, struct ds_status *st)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
|
err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -283,11 +283,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
|
||||||
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
|
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
|
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
|
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -297,7 +297,9 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ds_wait_status(struct ds_device *dev, struct ds_status *st)
|
#endif /* 0 */
|
||||||
|
|
||||||
|
static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
|
||||||
{
|
{
|
||||||
u8 buf[0x20];
|
u8 buf[0x20];
|
||||||
int err, count = 0;
|
int err, count = 0;
|
||||||
|
@ -305,7 +307,7 @@ int ds_wait_status(struct ds_device *dev, struct ds_status *st)
|
||||||
do {
|
do {
|
||||||
err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
|
err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
|
||||||
#if 0
|
#if 0
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
int i;
|
int i;
|
||||||
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
|
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
|
||||||
for (i=0; i<err; ++i)
|
for (i=0; i<err; ++i)
|
||||||
|
@ -319,10 +321,8 @@ int ds_wait_status(struct ds_device *dev, struct ds_status *st)
|
||||||
if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
|
if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
|
||||||
ds_recv_status(dev, st);
|
ds_recv_status(dev, st);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else
|
||||||
else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ds_reset(struct ds_device *dev, struct ds_status *st)
|
int ds_reset(struct ds_device *dev, struct ds_status *st)
|
||||||
|
@ -345,6 +345,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
int ds_set_speed(struct ds_device *dev, int speed)
|
int ds_set_speed(struct ds_device *dev, int speed)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -356,20 +357,21 @@ int ds_set_speed(struct ds_device *dev, int speed)
|
||||||
speed = SPEED_FLEXIBLE;
|
speed = SPEED_FLEXIBLE;
|
||||||
|
|
||||||
speed &= 0xff;
|
speed &= 0xff;
|
||||||
|
|
||||||
err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
|
err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
|
||||||
int ds_start_pulse(struct ds_device *dev, int delay)
|
static int ds_start_pulse(struct ds_device *dev, int delay)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u8 del = 1 + (u8)(delay >> 4);
|
u8 del = 1 + (u8)(delay >> 4);
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
err = ds_stop_pulse(dev, 10);
|
err = ds_stop_pulse(dev, 10);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -390,7 +392,7 @@ int ds_start_pulse(struct ds_device *dev, int delay)
|
||||||
mdelay(delay);
|
mdelay(delay);
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +402,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
|
u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
|
||||||
u16 cmd;
|
u16 cmd;
|
||||||
|
|
||||||
err = ds_send_control(dev, value, 0);
|
err = ds_send_control(dev, value, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -430,7 +432,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
|
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -445,7 +447,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte)
|
||||||
int err;
|
int err;
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
u8 rbyte;
|
u8 rbyte;
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
|
err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -453,11 +455,11 @@ int ds_write_byte(struct ds_device *dev, u8 byte)
|
||||||
err = ds_wait_status(dev, &st);
|
err = ds_wait_status(dev, &st);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
|
err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_start_pulse(dev, PULLUP_PULSE_DURATION);
|
ds_start_pulse(dev, PULLUP_PULSE_DURATION);
|
||||||
|
|
||||||
return !(byte == rbyte);
|
return !(byte == rbyte);
|
||||||
|
@ -470,11 +472,11 @@ int ds_read_bit(struct ds_device *dev, u8 *bit)
|
||||||
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
|
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
|
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_recv_data(dev, bit, sizeof(*bit));
|
err = ds_recv_data(dev, bit, sizeof(*bit));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -492,7 +494,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
err = ds_recv_data(dev, byte, sizeof(*byte));
|
err = ds_recv_data(dev, byte, sizeof(*byte));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -509,17 +511,17 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
memset(buf, 0xFF, len);
|
memset(buf, 0xFF, len);
|
||||||
|
|
||||||
err = ds_send_data(dev, buf, len);
|
err = ds_send_data(dev, buf, len);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
|
err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
memset(buf, 0x00, len);
|
memset(buf, 0x00, len);
|
||||||
err = ds_recv_data(dev, buf, len);
|
err = ds_recv_data(dev, buf, len);
|
||||||
|
|
||||||
|
@ -530,11 +532,11 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
err = ds_send_data(dev, buf, len);
|
err = ds_send_data(dev, buf, len);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
|
err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
|
||||||
|
@ -548,10 +550,12 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_start_pulse(dev, PULLUP_PULSE_DURATION);
|
ds_start_pulse(dev, PULLUP_PULSE_DURATION);
|
||||||
|
|
||||||
return !(err == len);
|
return !(err == len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
|
int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -559,11 +563,11 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
|
err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(ds_dev, &st);
|
ds_wait_status(ds_dev, &st);
|
||||||
|
|
||||||
value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
|
value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
|
||||||
|
@ -589,7 +593,7 @@ int ds_match_access(struct ds_device *dev, u64 init)
|
||||||
err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
|
err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
|
err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
|
||||||
|
@ -609,11 +613,11 @@ int ds_set_path(struct ds_device *dev, u64 init)
|
||||||
|
|
||||||
memcpy(buf, &init, 8);
|
memcpy(buf, &init, 8);
|
||||||
buf[8] = BRANCH_MAIN;
|
buf[8] = BRANCH_MAIN;
|
||||||
|
|
||||||
err = ds_send_data(dev, buf, sizeof(buf));
|
err = ds_send_data(dev, buf, sizeof(buf));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ds_wait_status(dev, &st);
|
ds_wait_status(dev, &st);
|
||||||
|
|
||||||
err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
|
err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
|
||||||
|
@ -625,7 +629,10 @@ int ds_set_path(struct ds_device *dev, u64 init)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
|
#endif /* 0 */
|
||||||
|
|
||||||
|
static int ds_probe(struct usb_interface *intf,
|
||||||
|
const struct usb_device_id *udev_id)
|
||||||
{
|
{
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
struct usb_device *udev = interface_to_usbdev(intf);
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
|
@ -653,7 +660,7 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
|
||||||
printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
|
printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
iface_desc = &intf->altsetting[0];
|
iface_desc = &intf->altsetting[0];
|
||||||
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
|
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
|
||||||
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
|
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
|
||||||
|
@ -662,37 +669,37 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
|
||||||
|
|
||||||
atomic_set(&ds_dev->refcnt, 0);
|
atomic_set(&ds_dev->refcnt, 0);
|
||||||
memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
|
memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This loop doesn'd show control 0 endpoint,
|
* This loop doesn'd show control 0 endpoint,
|
||||||
* so we will fill only 1-3 endpoints entry.
|
* so we will fill only 1-3 endpoints entry.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||||
endpoint = &iface_desc->endpoint[i].desc;
|
endpoint = &iface_desc->endpoint[i].desc;
|
||||||
|
|
||||||
ds_dev->ep[i+1] = endpoint->bEndpointAddress;
|
ds_dev->ep[i+1] = endpoint->bEndpointAddress;
|
||||||
|
|
||||||
printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
|
printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
|
||||||
i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
|
i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
|
||||||
(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
|
(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
|
||||||
endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
|
endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
int err, i;
|
int err, i;
|
||||||
u64 buf[3];
|
u64 buf[3];
|
||||||
u64 init=0xb30000002078ee81ull;
|
u64 init=0xb30000002078ee81ull;
|
||||||
struct ds_status st;
|
struct ds_status st;
|
||||||
|
|
||||||
ds_reset(ds_dev, &st);
|
ds_reset(ds_dev, &st);
|
||||||
err = ds_search(ds_dev, init, buf, 3, 0);
|
err = ds_search(ds_dev, init, buf, 3, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
for (i=0; i<err; ++i)
|
for (i=0; i<err; ++i)
|
||||||
printk("%d: %llx\n", i, buf[i]);
|
printk("%d: %llx\n", i, buf[i]);
|
||||||
|
|
||||||
printk("Resetting...\n");
|
printk("Resetting...\n");
|
||||||
ds_reset(ds_dev, &st);
|
ds_reset(ds_dev, &st);
|
||||||
printk("Setting path for %llx.\n", init);
|
printk("Setting path for %llx.\n", init);
|
||||||
err = ds_set_path(ds_dev, init);
|
err = ds_set_path(ds_dev, init);
|
||||||
|
@ -707,12 +714,12 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
|
||||||
err = ds_search(ds_dev, init, buf, 3, 0);
|
err = ds_search(ds_dev, init, buf, 3, 0);
|
||||||
|
|
||||||
printk("ds_search() returned %d\n", err);
|
printk("ds_search() returned %d\n", err);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
for (i=0; i<err; ++i)
|
for (i=0; i<err; ++i)
|
||||||
printk("%d: %llx\n", i, buf[i]);
|
printk("%d: %llx\n", i, buf[i]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -720,10 +727,10 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ds_disconnect(struct usb_interface *intf)
|
static void ds_disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct ds_device *dev;
|
struct ds_device *dev;
|
||||||
|
|
||||||
dev = usb_get_intfdata(intf);
|
dev = usb_get_intfdata(intf);
|
||||||
usb_set_intfdata(intf, NULL);
|
usb_set_intfdata(intf, NULL);
|
||||||
|
|
||||||
|
@ -740,7 +747,7 @@ void ds_disconnect(struct usb_interface *intf)
|
||||||
ds_dev = NULL;
|
ds_dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ds_init(void)
|
static int ds_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -753,7 +760,7 @@ int ds_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ds_fini(void)
|
static void ds_fini(void)
|
||||||
{
|
{
|
||||||
usb_deregister(&ds_driver);
|
usb_deregister(&ds_driver);
|
||||||
}
|
}
|
||||||
|
@ -776,8 +783,8 @@ EXPORT_SYMBOL(ds_get_device);
|
||||||
EXPORT_SYMBOL(ds_put_device);
|
EXPORT_SYMBOL(ds_put_device);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This functions can be used for EEPROM programming,
|
* This functions can be used for EEPROM programming,
|
||||||
* when driver will be included into mainline this will
|
* when driver will be included into mainline this will
|
||||||
* require uncommenting.
|
* require uncommenting.
|
||||||
*/
|
*/
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* dscore.h
|
* dscore.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
|
|
||||||
struct ds_device
|
struct ds_device
|
||||||
{
|
{
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
struct usb_interface *intf;
|
struct usb_interface *intf;
|
||||||
|
|
||||||
int ep[NUM_EP];
|
int ep[NUM_EP];
|
||||||
|
@ -156,11 +156,7 @@ int ds_read_byte(struct ds_device *, u8 *);
|
||||||
int ds_read_bit(struct ds_device *, u8 *);
|
int ds_read_bit(struct ds_device *, u8 *);
|
||||||
int ds_write_byte(struct ds_device *, u8);
|
int ds_write_byte(struct ds_device *, u8);
|
||||||
int ds_write_bit(struct ds_device *, u8);
|
int ds_write_bit(struct ds_device *, u8);
|
||||||
int ds_start_pulse(struct ds_device *, int);
|
|
||||||
int ds_set_speed(struct ds_device *, int);
|
|
||||||
int ds_reset(struct ds_device *, struct ds_status *);
|
int ds_reset(struct ds_device *, struct ds_status *);
|
||||||
int ds_detect(struct ds_device *, struct ds_status *);
|
|
||||||
int ds_stop_pulse(struct ds_device *, int);
|
|
||||||
struct ds_device * ds_get_device(void);
|
struct ds_device * ds_get_device(void);
|
||||||
void ds_put_device(struct ds_device *);
|
void ds_put_device(struct ds_device *);
|
||||||
int ds_write_block(struct ds_device *, u8 *, int);
|
int ds_write_block(struct ds_device *, u8 *, int);
|
||||||
|
|
302
drivers/w1/w1.c
302
drivers/w1/w1.c
|
@ -45,10 +45,12 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
|
||||||
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
|
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
|
||||||
|
|
||||||
static int w1_timeout = 10;
|
static int w1_timeout = 10;
|
||||||
|
static int w1_control_timeout = 1;
|
||||||
int w1_max_slave_count = 10;
|
int w1_max_slave_count = 10;
|
||||||
int w1_max_slave_ttl = 10;
|
int w1_max_slave_ttl = 10;
|
||||||
|
|
||||||
module_param_named(timeout, w1_timeout, int, 0);
|
module_param_named(timeout, w1_timeout, int, 0);
|
||||||
|
module_param_named(control_timeout, w1_control_timeout, int, 0);
|
||||||
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
|
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
|
||||||
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
|
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
|
||||||
|
|
||||||
|
@ -59,19 +61,6 @@ static pid_t control_thread;
|
||||||
static int control_needs_exit;
|
static int control_needs_exit;
|
||||||
static DECLARE_COMPLETION(w1_control_complete);
|
static DECLARE_COMPLETION(w1_control_complete);
|
||||||
|
|
||||||
/* stuff for the default family */
|
|
||||||
static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
|
||||||
return(sprintf(buf, "%s\n", sl->name));
|
|
||||||
}
|
|
||||||
static struct w1_family_ops w1_default_fops = {
|
|
||||||
.rname = &w1_famdefault_read_name,
|
|
||||||
};
|
|
||||||
static struct w1_family w1_default_family = {
|
|
||||||
.fops = &w1_default_fops,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int w1_master_match(struct device *dev, struct device_driver *drv)
|
static int w1_master_match(struct device *dev, struct device_driver *drv)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -82,73 +71,116 @@ static int w1_master_probe(struct device *dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w1_master_remove(struct device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void w1_master_release(struct device *dev)
|
static void w1_master_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
|
|
||||||
complete(&md->dev_released);
|
dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
|
||||||
|
|
||||||
|
if (md->nls && md->nls->sk_socket)
|
||||||
|
sock_release(md->nls->sk_socket);
|
||||||
|
memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
|
||||||
|
kfree(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void w1_slave_release(struct device *dev)
|
static void w1_slave_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||||
|
|
||||||
complete(&sl->dev_released);
|
dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
|
||||||
|
|
||||||
|
while (atomic_read(&sl->refcnt)) {
|
||||||
|
dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
|
||||||
|
sl->name, atomic_read(&sl->refcnt));
|
||||||
|
if (msleep_interruptible(1000))
|
||||||
|
flush_signals(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
w1_family_put(sl->family);
|
||||||
|
sl->master->slave_count--;
|
||||||
|
|
||||||
|
complete(&sl->released);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t w1_default_read_name(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "No family registered.\n");
|
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", sl->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off,
|
static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||||
size_t count)
|
|
||||||
{
|
{
|
||||||
return sprintf(buf, "No family registered.\n");
|
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||||
|
|
||||||
|
atomic_inc(&sl->refcnt);
|
||||||
|
if (off > 8) {
|
||||||
|
count = 0;
|
||||||
|
} else {
|
||||||
|
if (off + count > 8)
|
||||||
|
count = 8 - off;
|
||||||
|
|
||||||
|
memcpy(buf, (u8 *)&sl->reg_num, count);
|
||||||
|
}
|
||||||
|
atomic_dec(&sl->refcnt);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_attribute w1_slave_attribute =
|
static struct device_attribute w1_slave_attr_name =
|
||||||
__ATTR(name, S_IRUGO, w1_default_read_name, NULL);
|
__ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
|
||||||
|
|
||||||
static struct bin_attribute w1_slave_bin_attribute = {
|
static struct bin_attribute w1_slave_attr_bin_id = {
|
||||||
.attr = {
|
.attr = {
|
||||||
.name = "w1_slave",
|
.name = "id",
|
||||||
.mode = S_IRUGO,
|
.mode = S_IRUGO,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
.size = W1_SLAVE_DATA_SIZE,
|
.size = 8,
|
||||||
.read = &w1_default_read_bin,
|
.read = w1_slave_read_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Default family */
|
||||||
|
static struct w1_family w1_default_family;
|
||||||
|
|
||||||
|
static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
|
||||||
|
|
||||||
static struct bus_type w1_bus_type = {
|
static struct bus_type w1_bus_type = {
|
||||||
.name = "w1",
|
.name = "w1",
|
||||||
.match = w1_master_match,
|
.match = w1_master_match,
|
||||||
|
.hotplug = w1_hotplug,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct device_driver w1_driver = {
|
struct device_driver w1_master_driver = {
|
||||||
.name = "w1_driver",
|
.name = "w1_master_driver",
|
||||||
.bus = &w1_bus_type,
|
.bus = &w1_bus_type,
|
||||||
.probe = w1_master_probe,
|
.probe = w1_master_probe,
|
||||||
.remove = w1_master_remove,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct device w1_device = {
|
struct device w1_master_device = {
|
||||||
.parent = NULL,
|
.parent = NULL,
|
||||||
.bus = &w1_bus_type,
|
.bus = &w1_bus_type,
|
||||||
.bus_id = "w1 bus master",
|
.bus_id = "w1 bus master",
|
||||||
.driver = &w1_driver,
|
.driver = &w1_master_driver,
|
||||||
.release = &w1_master_release
|
.release = &w1_master_release
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct device_driver w1_slave_driver = {
|
||||||
|
.name = "w1_slave_driver",
|
||||||
|
.bus = &w1_bus_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device w1_slave_device = {
|
||||||
|
.parent = NULL,
|
||||||
|
.bus = &w1_bus_type,
|
||||||
|
.bus_id = "w1 bus slave",
|
||||||
|
.driver = &w1_slave_driver,
|
||||||
|
.release = &w1_slave_release
|
||||||
|
};
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible (&md->mutex))
|
if (down_interruptible (&md->mutex))
|
||||||
|
@ -165,7 +197,7 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char * buf, size_t count)
|
const char * buf, size_t count)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
|
|
||||||
if (down_interruptible (&md->mutex))
|
if (down_interruptible (&md->mutex))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -181,7 +213,7 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible (&md->mutex))
|
if (down_interruptible (&md->mutex))
|
||||||
|
@ -196,7 +228,7 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible(&md->mutex))
|
if (down_interruptible(&md->mutex))
|
||||||
|
@ -217,7 +249,7 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible(&md->mutex))
|
if (down_interruptible(&md->mutex))
|
||||||
|
@ -231,7 +263,7 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible(&md->mutex))
|
if (down_interruptible(&md->mutex))
|
||||||
|
@ -245,7 +277,7 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
if (down_interruptible(&md->mutex))
|
if (down_interruptible(&md->mutex))
|
||||||
|
@ -259,7 +291,7 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
|
||||||
|
|
||||||
static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct w1_master *md = container_of(dev, struct w1_master, dev);
|
struct w1_master *md = dev_to_w1_master(dev);
|
||||||
int c = PAGE_SIZE;
|
int c = PAGE_SIZE;
|
||||||
|
|
||||||
if (down_interruptible(&md->mutex))
|
if (down_interruptible(&md->mutex))
|
||||||
|
@ -329,12 +361,55 @@ void w1_destroy_master_attributes(struct w1_master *master)
|
||||||
sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
|
sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HOTPLUG
|
||||||
|
static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
struct w1_master *md = NULL;
|
||||||
|
struct w1_slave *sl = NULL;
|
||||||
|
char *event_owner, *name;
|
||||||
|
int err, cur_index=0, cur_len=0;
|
||||||
|
|
||||||
|
if (dev->driver == &w1_master_driver) {
|
||||||
|
md = container_of(dev, struct w1_master, dev);
|
||||||
|
event_owner = "master";
|
||||||
|
name = md->name;
|
||||||
|
} else if (dev->driver == &w1_slave_driver) {
|
||||||
|
sl = container_of(dev, struct w1_slave, dev);
|
||||||
|
event_owner = "slave";
|
||||||
|
name = sl->name;
|
||||||
|
} else {
|
||||||
|
dev_dbg(dev, "Unknown hotplug event.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id);
|
||||||
|
|
||||||
|
if (dev->driver != &w1_slave_driver || !sl)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __w1_attach_slave_device(struct w1_slave *sl)
|
static int __w1_attach_slave_device(struct w1_slave *sl)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sl->dev.parent = &sl->master->dev;
|
sl->dev.parent = &sl->master->dev;
|
||||||
sl->dev.driver = sl->master->driver;
|
sl->dev.driver = &w1_slave_driver;
|
||||||
sl->dev.bus = &w1_bus_type;
|
sl->dev.bus = &w1_bus_type;
|
||||||
sl->dev.release = &w1_slave_release;
|
sl->dev.release = &w1_slave_release;
|
||||||
|
|
||||||
|
@ -347,8 +422,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
|
||||||
(unsigned int) sl->reg_num.family,
|
(unsigned int) sl->reg_num.family,
|
||||||
(unsigned long long) sl->reg_num.id);
|
(unsigned long long) sl->reg_num.id);
|
||||||
|
|
||||||
dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
|
dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]);
|
||||||
&sl->dev.bus_id[0]);
|
|
||||||
|
|
||||||
err = device_register(&sl->dev);
|
err = device_register(&sl->dev);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -358,36 +432,44 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin));
|
/* Create "name" entry */
|
||||||
memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name));
|
err = device_create_file(&sl->dev, &w1_slave_attr_name);
|
||||||
|
|
||||||
sl->attr_bin.read = sl->family->fops->rbin;
|
|
||||||
sl->attr_name.show = sl->family->fops->rname;
|
|
||||||
|
|
||||||
err = device_create_file(&sl->dev, &sl->attr_name);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&sl->dev,
|
dev_err(&sl->dev,
|
||||||
"sysfs file creation for [%s] failed. err=%d\n",
|
"sysfs file creation for [%s] failed. err=%d\n",
|
||||||
sl->dev.bus_id, err);
|
sl->dev.bus_id, err);
|
||||||
device_unregister(&sl->dev);
|
goto out_unreg;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sl->attr_bin.read ) {
|
/* Create "id" entry */
|
||||||
err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
|
err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&sl->dev,
|
dev_err(&sl->dev,
|
||||||
"sysfs file creation for [%s] failed. err=%d\n",
|
"sysfs file creation for [%s] failed. err=%d\n",
|
||||||
sl->dev.bus_id, err);
|
sl->dev.bus_id, err);
|
||||||
device_remove_file(&sl->dev, &sl->attr_name);
|
goto out_rem1;
|
||||||
device_unregister(&sl->dev);
|
}
|
||||||
return err;
|
|
||||||
}
|
/* if the family driver needs to initialize something... */
|
||||||
|
if (sl->family->fops && sl->family->fops->add_slave &&
|
||||||
|
((err = sl->family->fops->add_slave(sl)) < 0)) {
|
||||||
|
dev_err(&sl->dev,
|
||||||
|
"sysfs file creation for [%s] failed. err=%d\n",
|
||||||
|
sl->dev.bus_id, err);
|
||||||
|
goto out_rem2;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
|
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_rem2:
|
||||||
|
sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
|
||||||
|
out_rem1:
|
||||||
|
device_remove_file(&sl->dev, &w1_slave_attr_name);
|
||||||
|
out_unreg:
|
||||||
|
device_unregister(&sl->dev);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
|
static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
|
||||||
|
@ -413,7 +495,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
|
||||||
|
|
||||||
memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
|
memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
|
||||||
atomic_set(&sl->refcnt, 0);
|
atomic_set(&sl->refcnt, 0);
|
||||||
init_completion(&sl->dev_released);
|
init_completion(&sl->released);
|
||||||
|
|
||||||
spin_lock(&w1_flock);
|
spin_lock(&w1_flock);
|
||||||
f = w1_family_registered(rn->family);
|
f = w1_family_registered(rn->family);
|
||||||
|
@ -452,28 +534,23 @@ static void w1_slave_detach(struct w1_slave *sl)
|
||||||
{
|
{
|
||||||
struct w1_netlink_msg msg;
|
struct w1_netlink_msg msg;
|
||||||
|
|
||||||
dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
|
dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl);
|
||||||
|
|
||||||
while (atomic_read(&sl->refcnt)) {
|
list_del(&sl->w1_slave_entry);
|
||||||
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
|
|
||||||
sl->name, atomic_read(&sl->refcnt));
|
|
||||||
|
|
||||||
if (msleep_interruptible(1000))
|
if (sl->family->fops && sl->family->fops->remove_slave)
|
||||||
flush_signals(current);
|
sl->family->fops->remove_slave(sl);
|
||||||
}
|
|
||||||
|
|
||||||
if ( sl->attr_bin.read ) {
|
|
||||||
sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
|
|
||||||
}
|
|
||||||
device_remove_file(&sl->dev, &sl->attr_name);
|
|
||||||
device_unregister(&sl->dev);
|
|
||||||
w1_family_put(sl->family);
|
|
||||||
|
|
||||||
sl->master->slave_count--;
|
|
||||||
|
|
||||||
memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
|
memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
|
||||||
msg.type = W1_SLAVE_REMOVE;
|
msg.type = W1_SLAVE_REMOVE;
|
||||||
w1_netlink_send(sl->master, &msg);
|
w1_netlink_send(sl->master, &msg);
|
||||||
|
|
||||||
|
sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
|
||||||
|
device_remove_file(&sl->dev, &w1_slave_attr_name);
|
||||||
|
device_unregister(&sl->dev);
|
||||||
|
|
||||||
|
wait_for_completion(&sl->released);
|
||||||
|
kfree(sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct w1_master *w1_search_master(unsigned long data)
|
static struct w1_master *w1_search_master(unsigned long data)
|
||||||
|
@ -500,14 +577,13 @@ void w1_reconnect_slaves(struct w1_family *f)
|
||||||
|
|
||||||
spin_lock_bh(&w1_mlock);
|
spin_lock_bh(&w1_mlock);
|
||||||
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
|
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
|
||||||
dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
|
dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
|
||||||
dev->name, f->fid);
|
dev->name, f->fid);
|
||||||
set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
|
set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&w1_mlock);
|
spin_unlock_bh(&w1_mlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void w1_slave_found(unsigned long data, u64 rn)
|
static void w1_slave_found(unsigned long data, u64 rn)
|
||||||
{
|
{
|
||||||
int slave_count;
|
int slave_count;
|
||||||
|
@ -646,7 +722,7 @@ static int w1_control(void *data)
|
||||||
have_to_wait = 0;
|
have_to_wait = 0;
|
||||||
|
|
||||||
try_to_freeze();
|
try_to_freeze();
|
||||||
msleep_interruptible(w1_timeout * 1000);
|
msleep_interruptible(w1_control_timeout * 1000);
|
||||||
|
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
|
@ -679,33 +755,30 @@ static int w1_control(void *data)
|
||||||
list_del(&dev->w1_master_entry);
|
list_del(&dev->w1_master_entry);
|
||||||
spin_unlock_bh(&w1_mlock);
|
spin_unlock_bh(&w1_mlock);
|
||||||
|
|
||||||
|
down(&dev->mutex);
|
||||||
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
|
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
|
||||||
list_del(&sl->w1_slave_entry);
|
|
||||||
|
|
||||||
w1_slave_detach(sl);
|
w1_slave_detach(sl);
|
||||||
kfree(sl);
|
|
||||||
}
|
}
|
||||||
w1_destroy_master_attributes(dev);
|
w1_destroy_master_attributes(dev);
|
||||||
|
up(&dev->mutex);
|
||||||
atomic_dec(&dev->refcnt);
|
atomic_dec(&dev->refcnt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
|
if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
|
||||||
dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
|
dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
|
||||||
down(&dev->mutex);
|
down(&dev->mutex);
|
||||||
list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
|
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
|
||||||
if (sl->family->fid == W1_FAMILY_DEFAULT) {
|
if (sl->family->fid == W1_FAMILY_DEFAULT) {
|
||||||
struct w1_reg_num rn;
|
struct w1_reg_num rn;
|
||||||
list_del(&sl->w1_slave_entry);
|
|
||||||
w1_slave_detach(sl);
|
|
||||||
|
|
||||||
memcpy(&rn, &sl->reg_num, sizeof(rn));
|
memcpy(&rn, &sl->reg_num, sizeof(rn));
|
||||||
|
w1_slave_detach(sl);
|
||||||
kfree(sl);
|
|
||||||
|
|
||||||
w1_attach_slave_device(dev, &rn);
|
w1_attach_slave_device(dev, &rn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
|
||||||
clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
|
clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
|
||||||
up(&dev->mutex);
|
up(&dev->mutex);
|
||||||
}
|
}
|
||||||
|
@ -749,10 +822,7 @@ int w1_process(void *data)
|
||||||
|
|
||||||
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
|
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
|
||||||
if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
|
if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
|
||||||
list_del (&sl->w1_slave_entry);
|
w1_slave_detach(sl);
|
||||||
|
|
||||||
w1_slave_detach (sl);
|
|
||||||
kfree (sl);
|
|
||||||
|
|
||||||
dev->slave_count--;
|
dev->slave_count--;
|
||||||
} else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
|
} else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
|
||||||
|
@ -783,7 +853,7 @@ static int w1_init(void)
|
||||||
goto err_out_exit_init;
|
goto err_out_exit_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = driver_register(&w1_driver);
|
retval = driver_register(&w1_master_driver);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"Failed to register master driver. err=%d.\n",
|
"Failed to register master driver. err=%d.\n",
|
||||||
|
@ -791,18 +861,29 @@ static int w1_init(void)
|
||||||
goto err_out_bus_unregister;
|
goto err_out_bus_unregister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retval = driver_register(&w1_slave_driver);
|
||||||
|
if (retval) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"Failed to register master driver. err=%d.\n",
|
||||||
|
retval);
|
||||||
|
goto err_out_master_unregister;
|
||||||
|
}
|
||||||
|
|
||||||
control_thread = kernel_thread(&w1_control, NULL, 0);
|
control_thread = kernel_thread(&w1_control, NULL, 0);
|
||||||
if (control_thread < 0) {
|
if (control_thread < 0) {
|
||||||
printk(KERN_ERR "Failed to create control thread. err=%d\n",
|
printk(KERN_ERR "Failed to create control thread. err=%d\n",
|
||||||
control_thread);
|
control_thread);
|
||||||
retval = control_thread;
|
retval = control_thread;
|
||||||
goto err_out_driver_unregister;
|
goto err_out_slave_unregister;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_driver_unregister:
|
err_out_slave_unregister:
|
||||||
driver_unregister(&w1_driver);
|
driver_unregister(&w1_slave_driver);
|
||||||
|
|
||||||
|
err_out_master_unregister:
|
||||||
|
driver_unregister(&w1_master_driver);
|
||||||
|
|
||||||
err_out_bus_unregister:
|
err_out_bus_unregister:
|
||||||
bus_unregister(&w1_bus_type);
|
bus_unregister(&w1_bus_type);
|
||||||
|
@ -821,7 +902,8 @@ static void w1_fini(void)
|
||||||
control_needs_exit = 1;
|
control_needs_exit = 1;
|
||||||
wait_for_completion(&w1_control_complete);
|
wait_for_completion(&w1_control_complete);
|
||||||
|
|
||||||
driver_unregister(&w1_driver);
|
driver_unregister(&w1_slave_driver);
|
||||||
|
driver_unregister(&w1_master_driver);
|
||||||
bus_unregister(&w1_bus_type);
|
bus_unregister(&w1_bus_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,11 +75,9 @@ struct w1_slave
|
||||||
|
|
||||||
struct w1_master *master;
|
struct w1_master *master;
|
||||||
struct w1_family *family;
|
struct w1_family *family;
|
||||||
|
void *family_data;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct completion dev_released;
|
struct completion released;
|
||||||
|
|
||||||
struct bin_attribute attr_bin;
|
|
||||||
struct device_attribute attr_name;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (* w1_slave_found_callback)(unsigned long, u64);
|
typedef void (* w1_slave_found_callback)(unsigned long, u64);
|
||||||
|
@ -179,7 +177,6 @@ struct w1_master
|
||||||
|
|
||||||
struct device_driver *driver;
|
struct device_driver *driver;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct completion dev_released;
|
|
||||||
struct completion dev_exited;
|
struct completion dev_exited;
|
||||||
|
|
||||||
struct w1_bus_master *bus_master;
|
struct w1_bus_master *bus_master;
|
||||||
|
@ -191,6 +188,21 @@ struct w1_master
|
||||||
int w1_create_master_attributes(struct w1_master *);
|
int w1_create_master_attributes(struct w1_master *);
|
||||||
void w1_search(struct w1_master *dev, w1_slave_found_callback cb);
|
void w1_search(struct w1_master *dev, w1_slave_found_callback cb);
|
||||||
|
|
||||||
|
static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
|
||||||
|
{
|
||||||
|
return container_of(dev, struct w1_slave, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct w1_slave* kobj_to_w1_slave(struct kobject *kobj)
|
||||||
|
{
|
||||||
|
return dev_to_w1_slave(container_of(kobj, struct device, kobj));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct w1_master* dev_to_w1_master(struct device *dev)
|
||||||
|
{
|
||||||
|
return container_of(dev, struct w1_master, dev);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
#endif /* __W1_H */
|
#endif /* __W1_H */
|
||||||
|
|
|
@ -0,0 +1,327 @@
|
||||||
|
/*
|
||||||
|
* w1_ds2433.c - w1 family 23 (DS2433) driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
#include <linux/crc16.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "w1.h"
|
||||||
|
#include "w1_io.h"
|
||||||
|
#include "w1_int.h"
|
||||||
|
#include "w1_family.h"
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
|
||||||
|
MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
|
||||||
|
|
||||||
|
#define W1_EEPROM_SIZE 512
|
||||||
|
#define W1_PAGE_COUNT 16
|
||||||
|
#define W1_PAGE_SIZE 32
|
||||||
|
#define W1_PAGE_BITS 5
|
||||||
|
#define W1_PAGE_MASK 0x1F
|
||||||
|
|
||||||
|
#define W1_F23_TIME 300
|
||||||
|
|
||||||
|
#define W1_F23_READ_EEPROM 0xF0
|
||||||
|
#define W1_F23_WRITE_SCRATCH 0x0F
|
||||||
|
#define W1_F23_READ_SCRATCH 0xAA
|
||||||
|
#define W1_F23_COPY_SCRATCH 0x55
|
||||||
|
|
||||||
|
struct w1_f23_data {
|
||||||
|
u8 memory[W1_EEPROM_SIZE];
|
||||||
|
u32 validcrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the file size bounds and adjusts count as needed.
|
||||||
|
* This would not be needed if the file size didn't reset to 0 after a write.
|
||||||
|
*/
|
||||||
|
static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
|
||||||
|
{
|
||||||
|
if (off > size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((off + count) > size)
|
||||||
|
return (size - off);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
|
||||||
|
int block)
|
||||||
|
{
|
||||||
|
u8 wrbuf[3];
|
||||||
|
int off = block * W1_PAGE_SIZE;
|
||||||
|
|
||||||
|
if (data->validcrc & (1 << block))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (w1_reset_select_slave(sl)) {
|
||||||
|
data->validcrc = 0;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrbuf[0] = W1_F23_READ_EEPROM;
|
||||||
|
wrbuf[1] = off & 0xff;
|
||||||
|
wrbuf[2] = off >> 8;
|
||||||
|
w1_write_block(sl->master, wrbuf, 3);
|
||||||
|
w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
|
||||||
|
|
||||||
|
/* cache the block if the CRC is valid */
|
||||||
|
if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
|
||||||
|
data->validcrc |= (1 << block);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
struct w1_f23_data *data = sl->family_data;
|
||||||
|
int i, min_page, max_page;
|
||||||
|
#else
|
||||||
|
u8 wrbuf[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
atomic_inc(&sl->refcnt);
|
||||||
|
if (down_interruptible(&sl->master->mutex)) {
|
||||||
|
count = 0;
|
||||||
|
goto out_dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
|
||||||
|
min_page = (off >> W1_PAGE_BITS);
|
||||||
|
max_page = (off + count - 1) >> W1_PAGE_BITS;
|
||||||
|
for (i = min_page; i <= max_page; i++) {
|
||||||
|
if (w1_f23_refresh_block(sl, data, i)) {
|
||||||
|
count = -EIO;
|
||||||
|
goto out_up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(buf, &data->memory[off], count);
|
||||||
|
|
||||||
|
#else /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
/* read directly from the EEPROM */
|
||||||
|
if (w1_reset_select_slave(sl)) {
|
||||||
|
count = -EIO;
|
||||||
|
goto out_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrbuf[0] = W1_F23_READ_EEPROM;
|
||||||
|
wrbuf[1] = off & 0xff;
|
||||||
|
wrbuf[2] = off >> 8;
|
||||||
|
w1_write_block(sl->master, wrbuf, 3);
|
||||||
|
w1_read_block(sl->master, buf, count);
|
||||||
|
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
out_up:
|
||||||
|
up(&sl->master->mutex);
|
||||||
|
out_dec:
|
||||||
|
atomic_dec(&sl->refcnt);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes to the scratchpad and reads it back for verification.
|
||||||
|
* Then copies the scratchpad to EEPROM.
|
||||||
|
* The data must be on one page.
|
||||||
|
* The master must be locked.
|
||||||
|
*
|
||||||
|
* @param sl The slave structure
|
||||||
|
* @param addr Address for the write
|
||||||
|
* @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
|
||||||
|
* @param data The data to write
|
||||||
|
* @return 0=Success -1=failure
|
||||||
|
*/
|
||||||
|
static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
|
||||||
|
{
|
||||||
|
u8 wrbuf[4];
|
||||||
|
u8 rdbuf[W1_PAGE_SIZE + 3];
|
||||||
|
u8 es = (addr + len - 1) & 0x1f;
|
||||||
|
|
||||||
|
/* Write the data to the scratchpad */
|
||||||
|
if (w1_reset_select_slave(sl))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wrbuf[0] = W1_F23_WRITE_SCRATCH;
|
||||||
|
wrbuf[1] = addr & 0xff;
|
||||||
|
wrbuf[2] = addr >> 8;
|
||||||
|
|
||||||
|
w1_write_block(sl->master, wrbuf, 3);
|
||||||
|
w1_write_block(sl->master, data, len);
|
||||||
|
|
||||||
|
/* Read the scratchpad and verify */
|
||||||
|
if (w1_reset_select_slave(sl))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
w1_write_8(sl->master, W1_F23_READ_SCRATCH);
|
||||||
|
w1_read_block(sl->master, rdbuf, len + 3);
|
||||||
|
|
||||||
|
/* Compare what was read against the data written */
|
||||||
|
if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
|
||||||
|
(rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Copy the scratchpad to EEPROM */
|
||||||
|
if (w1_reset_select_slave(sl))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wrbuf[0] = W1_F23_COPY_SCRATCH;
|
||||||
|
wrbuf[3] = es;
|
||||||
|
w1_write_block(sl->master, wrbuf, 4);
|
||||||
|
|
||||||
|
/* Sleep for 5 ms to wait for the write to complete */
|
||||||
|
msleep(5);
|
||||||
|
|
||||||
|
/* Reset the bus to wake up the EEPROM (this may not be needed) */
|
||||||
|
w1_reset_bus(sl->master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||||
|
int addr, len, idx;
|
||||||
|
|
||||||
|
if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
/* can only write full blocks in cached mode */
|
||||||
|
if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
|
||||||
|
dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n",
|
||||||
|
(int)off, count);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure the block CRCs are valid */
|
||||||
|
for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
|
||||||
|
if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
|
||||||
|
dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
atomic_inc(&sl->refcnt);
|
||||||
|
if (down_interruptible(&sl->master->mutex)) {
|
||||||
|
count = 0;
|
||||||
|
goto out_dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can only write data to one page at a time */
|
||||||
|
idx = 0;
|
||||||
|
while (idx < count) {
|
||||||
|
addr = off + idx;
|
||||||
|
len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
|
||||||
|
if (len > (count - idx))
|
||||||
|
len = count - idx;
|
||||||
|
|
||||||
|
if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
|
||||||
|
count = -EIO;
|
||||||
|
goto out_up;
|
||||||
|
}
|
||||||
|
idx += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_up:
|
||||||
|
up(&sl->master->mutex);
|
||||||
|
out_dec:
|
||||||
|
atomic_dec(&sl->refcnt);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bin_attribute w1_f23_bin_attr = {
|
||||||
|
.attr = {
|
||||||
|
.name = "eeprom",
|
||||||
|
.mode = S_IRUGO | S_IWUSR,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.size = W1_EEPROM_SIZE,
|
||||||
|
.read = w1_f23_read_bin,
|
||||||
|
.write = w1_f23_write_bin,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int w1_f23_add_slave(struct w1_slave *sl)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
struct w1_f23_data *data;
|
||||||
|
|
||||||
|
data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
memset(data, 0, sizeof(struct w1_f23_data));
|
||||||
|
sl->family_data = data;
|
||||||
|
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
|
||||||
|
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
if (err)
|
||||||
|
kfree(data);
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void w1_f23_remove_slave(struct w1_slave *sl)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_W1_F23_CRC
|
||||||
|
if (sl->family_data) {
|
||||||
|
kfree(sl->family_data);
|
||||||
|
sl->family_data = NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_W1_F23_CRC */
|
||||||
|
sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct w1_family_ops w1_f23_fops = {
|
||||||
|
.add_slave = w1_f23_add_slave,
|
||||||
|
.remove_slave = w1_f23_remove_slave,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct w1_family w1_family_23 = {
|
||||||
|
.fid = W1_EEPROM_DS2433,
|
||||||
|
.fops = &w1_f23_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init w1_f23_init(void)
|
||||||
|
{
|
||||||
|
return w1_register_family(&w1_family_23);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit w1_f23_fini(void)
|
||||||
|
{
|
||||||
|
w1_unregister_family(&w1_family_23);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(w1_f23_init);
|
||||||
|
module_exit(w1_f23_fini);
|
|
@ -29,23 +29,12 @@ DEFINE_SPINLOCK(w1_flock);
|
||||||
static LIST_HEAD(w1_families);
|
static LIST_HEAD(w1_families);
|
||||||
extern void w1_reconnect_slaves(struct w1_family *f);
|
extern void w1_reconnect_slaves(struct w1_family *f);
|
||||||
|
|
||||||
static int w1_check_family(struct w1_family *f)
|
|
||||||
{
|
|
||||||
if (!f->fops->rname || !f->fops->rbin)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int w1_register_family(struct w1_family *newf)
|
int w1_register_family(struct w1_family *newf)
|
||||||
{
|
{
|
||||||
struct list_head *ent, *n;
|
struct list_head *ent, *n;
|
||||||
struct w1_family *f;
|
struct w1_family *f;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (w1_check_family(newf))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
spin_lock(&w1_flock);
|
spin_lock(&w1_flock);
|
||||||
list_for_each_safe(ent, n, &w1_families) {
|
list_for_each_safe(ent, n, &w1_families) {
|
||||||
f = list_entry(ent, struct w1_family, family_entry);
|
f = list_entry(ent, struct w1_family, family_entry);
|
||||||
|
|
|
@ -31,14 +31,17 @@
|
||||||
#define W1_FAMILY_SMEM_81 0x81
|
#define W1_FAMILY_SMEM_81 0x81
|
||||||
#define W1_THERM_DS18S20 0x10
|
#define W1_THERM_DS18S20 0x10
|
||||||
#define W1_THERM_DS1822 0x22
|
#define W1_THERM_DS1822 0x22
|
||||||
|
#define W1_EEPROM_DS2433 0x23
|
||||||
#define W1_THERM_DS18B20 0x28
|
#define W1_THERM_DS18B20 0x28
|
||||||
|
|
||||||
#define MAXNAMELEN 32
|
#define MAXNAMELEN 32
|
||||||
|
|
||||||
|
struct w1_slave;
|
||||||
|
|
||||||
struct w1_family_ops
|
struct w1_family_ops
|
||||||
{
|
{
|
||||||
ssize_t (* rname)(struct device *, struct device_attribute *, char *);
|
int (* add_slave)(struct w1_slave *);
|
||||||
ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t);
|
void (* remove_slave)(struct w1_slave *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct w1_family
|
struct w1_family
|
||||||
|
|
|
@ -29,9 +29,9 @@
|
||||||
|
|
||||||
static u32 w1_ids = 1;
|
static u32 w1_ids = 1;
|
||||||
|
|
||||||
extern struct device_driver w1_driver;
|
extern struct device_driver w1_master_driver;
|
||||||
extern struct bus_type w1_bus_type;
|
extern struct bus_type w1_bus_type;
|
||||||
extern struct device w1_device;
|
extern struct device w1_master_device;
|
||||||
extern int w1_max_slave_count;
|
extern int w1_max_slave_count;
|
||||||
extern int w1_max_slave_ttl;
|
extern int w1_max_slave_ttl;
|
||||||
extern struct list_head w1_masters;
|
extern struct list_head w1_masters;
|
||||||
|
@ -76,7 +76,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
||||||
INIT_LIST_HEAD(&dev->slist);
|
INIT_LIST_HEAD(&dev->slist);
|
||||||
init_MUTEX(&dev->mutex);
|
init_MUTEX(&dev->mutex);
|
||||||
|
|
||||||
init_completion(&dev->dev_released);
|
|
||||||
init_completion(&dev->dev_exited);
|
init_completion(&dev->dev_exited);
|
||||||
|
|
||||||
memcpy(&dev->dev, device, sizeof(struct device));
|
memcpy(&dev->dev, device, sizeof(struct device));
|
||||||
|
@ -88,17 +87,14 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
||||||
|
|
||||||
dev->groups = 1;
|
dev->groups = 1;
|
||||||
dev->seq = 1;
|
dev->seq = 1;
|
||||||
dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
|
dev_init_netlink(dev);
|
||||||
if (!dev->nls) {
|
|
||||||
printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
|
|
||||||
NETLINK_NFLOG, dev->dev.bus_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = device_register(&dev->dev);
|
err = device_register(&dev->dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "Failed to register master device. err=%d\n", err);
|
printk(KERN_ERR "Failed to register master device. err=%d\n", err);
|
||||||
if (dev->nls && dev->nls->sk_socket)
|
|
||||||
sock_release(dev->nls->sk_socket);
|
dev_fini_netlink(dev);
|
||||||
|
|
||||||
memset(dev, 0, sizeof(struct w1_master));
|
memset(dev, 0, sizeof(struct w1_master));
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
|
@ -107,13 +103,9 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void w1_free_dev(struct w1_master *dev)
|
void w1_free_dev(struct w1_master *dev)
|
||||||
{
|
{
|
||||||
device_unregister(&dev->dev);
|
device_unregister(&dev->dev);
|
||||||
if (dev->nls && dev->nls->sk_socket)
|
|
||||||
sock_release(dev->nls->sk_socket);
|
|
||||||
memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
|
|
||||||
kfree(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int w1_add_master_device(struct w1_bus_master *master)
|
int w1_add_master_device(struct w1_bus_master *master)
|
||||||
|
@ -129,7 +121,7 @@ int w1_add_master_device(struct w1_bus_master *master)
|
||||||
return(-EINVAL);
|
return(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
|
dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -188,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev)
|
||||||
__func__, dev->kpid);
|
__func__, dev->kpid);
|
||||||
|
|
||||||
while (atomic_read(&dev->refcnt)) {
|
while (atomic_read(&dev->refcnt)) {
|
||||||
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
|
dev_dbg(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
|
||||||
dev->name, atomic_read(&dev->refcnt));
|
dev->name, atomic_read(&dev->refcnt));
|
||||||
|
|
||||||
if (msleep_interruptible(1000))
|
if (msleep_interruptible(1000))
|
||||||
|
|
|
@ -277,6 +277,29 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
|
||||||
w1_search(dev, cb);
|
w1_search(dev, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the bus and then selects the slave by sending either a skip rom
|
||||||
|
* or a rom match.
|
||||||
|
* The w1 master lock must be held.
|
||||||
|
*
|
||||||
|
* @param sl the slave to select
|
||||||
|
* @return 0=success, anything else=error
|
||||||
|
*/
|
||||||
|
int w1_reset_select_slave(struct w1_slave *sl)
|
||||||
|
{
|
||||||
|
if (w1_reset_bus(sl->master))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sl->master->slave_count == 1)
|
||||||
|
w1_write_8(sl->master, W1_SKIP_ROM);
|
||||||
|
else {
|
||||||
|
u8 match[9] = {W1_MATCH_ROM, };
|
||||||
|
memcpy(&match[1], (u8 *)&sl->reg_num, 8);
|
||||||
|
w1_write_block(sl->master, match, 9);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(w1_touch_bit);
|
EXPORT_SYMBOL(w1_touch_bit);
|
||||||
EXPORT_SYMBOL(w1_write_8);
|
EXPORT_SYMBOL(w1_write_8);
|
||||||
EXPORT_SYMBOL(w1_read_8);
|
EXPORT_SYMBOL(w1_read_8);
|
||||||
|
@ -286,3 +309,4 @@ EXPORT_SYMBOL(w1_delay);
|
||||||
EXPORT_SYMBOL(w1_read_block);
|
EXPORT_SYMBOL(w1_read_block);
|
||||||
EXPORT_SYMBOL(w1_write_block);
|
EXPORT_SYMBOL(w1_write_block);
|
||||||
EXPORT_SYMBOL(w1_search_devices);
|
EXPORT_SYMBOL(w1_search_devices);
|
||||||
|
EXPORT_SYMBOL(w1_reset_select_slave);
|
||||||
|
|
|
@ -34,5 +34,6 @@ u8 w1_calc_crc8(u8 *, int);
|
||||||
void w1_write_block(struct w1_master *, const u8 *, int);
|
void w1_write_block(struct w1_master *, const u8 *, int);
|
||||||
u8 w1_read_block(struct w1_master *, u8 *, int);
|
u8 w1_read_block(struct w1_master *, u8 *, int);
|
||||||
void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
|
void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
|
||||||
|
int w1_reset_select_slave(struct w1_slave *sl);
|
||||||
|
|
||||||
#endif /* __W1_IO_H */
|
#endif /* __W1_IO_H */
|
||||||
|
|
|
@ -57,10 +57,36 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
|
||||||
nlmsg_failure:
|
nlmsg_failure:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dev_init_netlink(struct w1_master *dev)
|
||||||
|
{
|
||||||
|
dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
|
||||||
|
if (!dev->nls) {
|
||||||
|
printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
|
||||||
|
NETLINK_W1, dev->dev.bus_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_fini_netlink(struct w1_master *dev)
|
||||||
|
{
|
||||||
|
if (dev->nls && dev->nls->sk_socket)
|
||||||
|
sock_release(dev->nls->sk_socket);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#warning Netlink support is disabled. Please compile with NET support enabled.
|
#warning Netlink support is disabled. Please compile with NET support enabled.
|
||||||
|
|
||||||
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
|
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dev_init_netlink(struct w1_master *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_fini_netlink(struct w1_master *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,6 +52,8 @@ struct w1_netlink_msg
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
|
void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
|
||||||
|
int dev_init_netlink(struct w1_master *dev);
|
||||||
|
void dev_fini_netlink(struct w1_master *dev);
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
#endif /* __W1_NETLINK_H */
|
#endif /* __W1_NETLINK_H */
|
||||||
|
|
|
@ -36,61 +36,12 @@ MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
|
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
|
||||||
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
|
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
|
||||||
|
|
||||||
static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *);
|
|
||||||
static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);
|
|
||||||
|
|
||||||
static struct w1_family_ops w1_smem_fops = {
|
|
||||||
.rname = &w1_smem_read_name,
|
|
||||||
.rbin = &w1_smem_read_bin,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", sl->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
|
|
||||||
struct w1_slave, dev);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
atomic_inc(&sl->refcnt);
|
|
||||||
if (down_interruptible(&sl->master->mutex)) {
|
|
||||||
count = 0;
|
|
||||||
goto out_dec;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (off > W1_SLAVE_DATA_SIZE) {
|
|
||||||
count = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (off + count > W1_SLAVE_DATA_SIZE) {
|
|
||||||
count = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
for (i = 0; i < 8; ++i)
|
|
||||||
count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
|
|
||||||
count += sprintf(buf + count, "\n");
|
|
||||||
|
|
||||||
out:
|
|
||||||
up(&sl->master->mutex);
|
|
||||||
out_dec:
|
|
||||||
atomic_dec(&sl->refcnt);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct w1_family w1_smem_family_01 = {
|
static struct w1_family w1_smem_family_01 = {
|
||||||
.fid = W1_FAMILY_SMEM_01,
|
.fid = W1_FAMILY_SMEM_01,
|
||||||
.fops = &w1_smem_fops,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct w1_family w1_smem_family_81 = {
|
static struct w1_family w1_smem_family_81 = {
|
||||||
.fid = W1_FAMILY_SMEM_81,
|
.fid = W1_FAMILY_SMEM_81,
|
||||||
.fops = &w1_smem_fops,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init w1_smem_init(void)
|
static int __init w1_smem_init(void)
|
||||||
|
|
|
@ -42,12 +42,31 @@ static u8 bad_roms[][9] = {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *);
|
|
||||||
static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
|
static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
|
||||||
|
|
||||||
|
static struct bin_attribute w1_therm_bin_attr = {
|
||||||
|
.attr = {
|
||||||
|
.name = "w1_slave",
|
||||||
|
.mode = S_IRUGO,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.size = W1_SLAVE_DATA_SIZE,
|
||||||
|
.read = w1_therm_read_bin,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int w1_therm_add_slave(struct w1_slave *sl)
|
||||||
|
{
|
||||||
|
return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void w1_therm_remove_slave(struct w1_slave *sl)
|
||||||
|
{
|
||||||
|
sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
|
||||||
|
}
|
||||||
|
|
||||||
static struct w1_family_ops w1_therm_fops = {
|
static struct w1_family_ops w1_therm_fops = {
|
||||||
.rname = &w1_therm_read_name,
|
.add_slave = w1_therm_add_slave,
|
||||||
.rbin = &w1_therm_read_bin,
|
.remove_slave = w1_therm_remove_slave,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct w1_family w1_therm_family_DS18S20 = {
|
static struct w1_family w1_therm_family_DS18S20 = {
|
||||||
|
@ -59,6 +78,7 @@ static struct w1_family w1_therm_family_DS18B20 = {
|
||||||
.fid = W1_THERM_DS18B20,
|
.fid = W1_THERM_DS18B20,
|
||||||
.fops = &w1_therm_fops,
|
.fops = &w1_therm_fops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct w1_family w1_therm_family_DS1822 = {
|
static struct w1_family w1_therm_family_DS1822 = {
|
||||||
.fid = W1_THERM_DS1822,
|
.fid = W1_THERM_DS1822,
|
||||||
.fops = &w1_therm_fops,
|
.fops = &w1_therm_fops,
|
||||||
|
@ -90,13 +110,6 @@ static struct w1_therm_family_converter w1_therm_families[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", sl->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int w1_DS18B20_convert_temp(u8 rom[9])
|
static inline int w1_DS18B20_convert_temp(u8 rom[9])
|
||||||
{
|
{
|
||||||
int t = (rom[1] << 8) | rom[0];
|
int t = (rom[1] << 8) | rom[0];
|
||||||
|
@ -148,8 +161,7 @@ static int w1_therm_check_rom(u8 rom[9])
|
||||||
|
|
||||||
static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||||
{
|
{
|
||||||
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
|
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||||
struct w1_slave, dev);
|
|
||||||
struct w1_master *dev = sl->master;
|
struct w1_master *dev = sl->master;
|
||||||
u8 rom[9], crc, verdict;
|
u8 rom[9], crc, verdict;
|
||||||
int i, max_trying = 10;
|
int i, max_trying = 10;
|
||||||
|
@ -178,15 +190,10 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
|
||||||
crc = 0;
|
crc = 0;
|
||||||
|
|
||||||
while (max_trying--) {
|
while (max_trying--) {
|
||||||
if (!w1_reset_bus (dev)) {
|
if (!w1_reset_select_slave(sl)) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
u8 match[9] = {W1_MATCH_ROM, };
|
|
||||||
unsigned int tm = 750;
|
unsigned int tm = 750;
|
||||||
|
|
||||||
memcpy(&match[1], (u64 *) & sl->reg_num, 8);
|
|
||||||
|
|
||||||
w1_write_block(dev, match, 9);
|
|
||||||
|
|
||||||
w1_write_8(dev, W1_CONVERT_TEMP);
|
w1_write_8(dev, W1_CONVERT_TEMP);
|
||||||
|
|
||||||
while (tm) {
|
while (tm) {
|
||||||
|
@ -195,8 +202,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!w1_reset_bus (dev)) {
|
if (!w1_reset_select_slave(sl)) {
|
||||||
w1_write_block(dev, match, 9);
|
|
||||||
|
|
||||||
w1_write_8(dev, W1_READ_SCRATCHPAD);
|
w1_write_8(dev, W1_READ_SCRATCHPAD);
|
||||||
if ((count = w1_read_block(dev, rom, 9)) != 9) {
|
if ((count = w1_read_block(dev, rom, 9)) != 9) {
|
||||||
|
@ -207,7 +213,6 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
|
||||||
|
|
||||||
if (rom[8] == crc && rom[0])
|
if (rom[8] == crc && rom[0])
|
||||||
verdict = 1;
|
verdict = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* crc16.h - CRC-16 routine
|
||||||
|
*
|
||||||
|
* Implements the standard CRC-16, as used with 1-wire devices:
|
||||||
|
* Width 16
|
||||||
|
* Poly 0x8005 (x^16 + x^15 + x^2 + 1)
|
||||||
|
* Init 0
|
||||||
|
*
|
||||||
|
* For 1-wire devices, the CRC is stored inverted, LSB-first
|
||||||
|
*
|
||||||
|
* Example buffer with the CRC attached:
|
||||||
|
* 31 32 33 34 35 36 37 38 39 C2 44
|
||||||
|
*
|
||||||
|
* The CRC over a buffer with the CRC attached is 0xB001.
|
||||||
|
* So, if (crc16(0, buf, size) == 0xB001) then the buffer is valid.
|
||||||
|
*
|
||||||
|
* Refer to "Application Note 937: Book of iButton Standards" for details.
|
||||||
|
* http://www.maxim-ic.com/appnotes.cfm/appnote_number/937
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CRC16_H
|
||||||
|
#define __CRC16_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define CRC16_INIT 0
|
||||||
|
#define CRC16_VALID 0xb001
|
||||||
|
|
||||||
|
extern u16 const crc16_table[256];
|
||||||
|
|
||||||
|
extern u16 crc16(u16 crc, const u8 *buffer, size_t len);
|
||||||
|
|
||||||
|
static inline u16 crc16_byte(u16 crc, const u8 data)
|
||||||
|
{
|
||||||
|
return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __CRC16_H */
|
||||||
|
|
|
@ -12,6 +12,14 @@ config CRC_CCITT
|
||||||
the kernel tree does. Such modules that use library CRC-CCITT
|
the kernel tree does. Such modules that use library CRC-CCITT
|
||||||
functions require M here.
|
functions require M here.
|
||||||
|
|
||||||
|
config CRC16
|
||||||
|
tristate "CRC16 functions"
|
||||||
|
help
|
||||||
|
This option is provided for the case where no in-kernel-tree
|
||||||
|
modules require CRC16 functions, but a module built outside
|
||||||
|
the kernel tree does. Such modules that use library CRC16
|
||||||
|
functions require M here.
|
||||||
|
|
||||||
config CRC32
|
config CRC32
|
||||||
tristate "CRC32 functions"
|
tristate "CRC32 functions"
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -23,11 +23,12 @@ lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
|
||||||
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
|
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
|
||||||
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
|
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
|
||||||
|
|
||||||
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
|
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
|
||||||
lib-y += dec_and_lock.o
|
lib-y += dec_and_lock.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
|
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
|
||||||
|
obj-$(CONFIG_CRC16) += crc16.o
|
||||||
obj-$(CONFIG_CRC32) += crc32.o
|
obj-$(CONFIG_CRC32) += crc32.o
|
||||||
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
|
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
|
||||||
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
|
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* crc16.c
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/crc16.h>
|
||||||
|
|
||||||
|
/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
|
||||||
|
u16 const crc16_table[256] = {
|
||||||
|
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||||
|
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||||
|
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||||
|
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||||
|
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||||
|
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||||
|
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||||
|
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||||
|
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||||
|
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||||
|
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||||
|
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||||
|
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||||
|
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||||
|
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||||
|
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||||
|
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||||
|
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||||
|
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||||
|
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||||
|
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||||
|
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||||
|
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||||
|
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||||
|
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||||
|
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||||
|
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||||
|
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||||
|
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||||
|
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||||
|
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||||
|
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL(crc16_table);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the CRC-16 for the data buffer
|
||||||
|
*
|
||||||
|
* @param crc previous CRC value
|
||||||
|
* @param buffer data pointer
|
||||||
|
* @param len number of bytes in the buffer
|
||||||
|
* @return the updated CRC value
|
||||||
|
*/
|
||||||
|
u16 crc16(u16 crc, u8 const *buffer, size_t len)
|
||||||
|
{
|
||||||
|
while (len--)
|
||||||
|
crc = crc16_byte(crc, *buffer++);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(crc16);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("CRC16 calculations");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
Loading…
Reference in New Issue