diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-31 16:24:15 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-31 16:24:15 -0800 |
commit | 4e94b51afd61703d88e6d84451fd2bbd10efbeaa (patch) | |
tree | 8905e95ee236a20d9aab1272db4ef1b8e1aa20d0 /i2c | |
parent | f58ad68f00c1744fddbf67fd7467912ae6b42eae (diff) | |
download | patches-4e94b51afd61703d88e6d84451fd2bbd10efbeaa.tar.gz |
more patches
Diffstat (limited to 'i2c')
5 files changed, 3458 insertions, 0 deletions
diff --git a/i2c/w1-added-default-generic-read-write-operations.patch b/i2c/w1-added-default-generic-read-write-operations.patch new file mode 100644 index 0000000000000..87cce1b0c6efc --- /dev/null +++ b/i2c/w1-added-default-generic-read-write-operations.patch @@ -0,0 +1,155 @@ +From johnpol@2ka.mipt.ru Thu Mar 23 07:59:58 2006 +Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Subject: [PATCH 1/5] w1: Added default generic read/write operations. +Date: Thu, 23 Mar 2006 19:11:58 +0300 +Message-Id: <11431303182664@2ka.mipt.ru> +To: GregKH <greg@kroah.com> +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> + + +Special file in each w1 slave device's directory called "rw" is created +each time new slave and no appropriate w1 family is registered. +"rw" file supports read and write operations, which allows to perform +almost any kind of operations. Each logical operation is a transaction +in nature, which can contain several (two or one) low-level operations. +Let's see how one can read EEPROM context: +1. one must write control buffer, i.e. buffer containing command byte +and two byte address. At this step bus is reset and appropriate device +is selected using either W1_SKIP_ROM or W1_MATCH_ROM command. +Then provided control buffer is being written to the wire. +2. reading. This will issue reading eeprom response. + +It is possible that between 1. and 2. w1 master thread will reset bus for +searching and slave device will be even removed, but in this case 0xff will +be read, since no device was selected. + +Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + Documentation/w1/w1.generic | 18 +++++++++-- + drivers/w1/w1.c | 69 +++++++++++++++++++++++++++++++++++++++++++- + drivers/w1/w1.h | 2 - + 3 files changed, 84 insertions(+), 5 deletions(-) + +--- gregkh-2.6.orig/Documentation/w1/w1.generic ++++ gregkh-2.6/Documentation/w1/w1.generic +@@ -27,8 +27,19 @@ When a w1 master driver registers with t + + When a device is found on the bus, w1 core checks if driver for it's family is + loaded. If so, the family driver is attached to the slave. +-If there is no driver for the family, a simple sysfs entry is created +-for the slave device. ++If there is no driver for the family, default one is assigned, which allows to perform ++almost any kind of operations. Each logical operation is a transaction ++in nature, which can contain several (two or one) low-level operations. ++Let's see how one can read EEPROM context: ++1. one must write control buffer, i.e. buffer containing command byte ++and two byte address. At this step bus is reset and appropriate device ++is selected using either W1_SKIP_ROM or W1_MATCH_ROM command. ++Then provided control buffer is being written to the wire. ++2. reading. This will issue reading eeprom response. ++ ++It is possible that between 1. and 2. w1 master thread will reset bus for searching ++and slave device will be even removed, but in this case 0xff will ++be read, since no device was selected. + + + W1 device families +@@ -89,4 +100,5 @@ driver - (standard) symlink + name - the device name, usually the same as the directory name + w1_slave - (optional) a binary file whose meaning depends on the + family driver +- ++rw - (optional) created for slave devices which do not have ++ appropriate family driver. Allows to read/write binary data. +--- gregkh-2.6.orig/drivers/w1/w1.c ++++ gregkh-2.6/drivers/w1/w1.c +@@ -139,7 +139,74 @@ static struct bin_attribute w1_slave_att + }; + + /* Default family */ +-static struct w1_family w1_default_family; ++ ++static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count) ++{ ++ struct w1_slave *sl = kobj_to_w1_slave(kobj); ++ ++ if (down_interruptible(&sl->master->mutex)) { ++ count = 0; ++ goto out; ++ } ++ ++ if (w1_reset_select_slave(sl)) { ++ count = 0; ++ goto out_up; ++ } ++ ++ w1_write_block(sl->master, buf, count); ++ ++out_up: ++ up(&sl->master->mutex); ++out: ++ return count; ++} ++ ++static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count) ++{ ++ struct w1_slave *sl = kobj_to_w1_slave(kobj); ++ ++ if (down_interruptible(&sl->master->mutex)) { ++ count = 0; ++ goto out; ++ } ++ ++ w1_read_block(sl->master, buf, count); ++ ++ up(&sl->master->mutex); ++out: ++ return count; ++} ++ ++static struct bin_attribute w1_default_attr = { ++ .attr = { ++ .name = "rw", ++ .mode = S_IRUGO | S_IWUSR, ++ .owner = THIS_MODULE, ++ }, ++ .size = PAGE_SIZE, ++ .read = w1_default_read, ++ .write = w1_default_write, ++}; ++ ++static int w1_default_add_slave(struct w1_slave *sl) ++{ ++ return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr); ++} ++ ++static void w1_default_remove_slave(struct w1_slave *sl) ++{ ++ sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr); ++} ++ ++static struct w1_family_ops w1_default_fops = { ++ .add_slave = w1_default_add_slave, ++ .remove_slave = w1_default_remove_slave, ++}; ++ ++static struct w1_family w1_default_family = { ++ .fops = &w1_default_fops, ++}; + + static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); + +--- gregkh-2.6.orig/drivers/w1/w1.h ++++ gregkh-2.6/drivers/w1/w1.h +@@ -60,7 +60,7 @@ struct w1_reg_num + #define W1_READ_PSUPPLY 0xB4 + #define W1_MATCH_ROM 0x55 + +-#define W1_SLAVE_ACTIVE (1<<0) ++#define W1_SLAVE_ACTIVE 0 + + struct w1_slave + { diff --git a/i2c/w1-move-w1-connector-definitions-into-linux-include-connector.h.patch b/i2c/w1-move-w1-connector-definitions-into-linux-include-connector.h.patch new file mode 100644 index 0000000000000..6f7f458703e22 --- /dev/null +++ b/i2c/w1-move-w1-connector-definitions-into-linux-include-connector.h.patch @@ -0,0 +1,44 @@ +From johnpol@2ka.mipt.ru Thu Mar 23 08:00:09 2006 +Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Subject: [PATCH 4/5] w1: Move w1-connector definitions into linux/include/connector.h +Date: Thu, 23 Mar 2006 19:11:58 +0300 +Message-Id: <11431303183514@2ka.mipt.ru> +To: GregKH <greg@kroah.com> +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> + + +Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/w1/w1_netlink.h | 3 --- + include/linux/connector.h | 5 ++++- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- gregkh-2.6.orig/drivers/w1/w1_netlink.h ++++ gregkh-2.6/drivers/w1/w1_netlink.h +@@ -27,9 +27,6 @@ + + #include "w1.h" + +-#define CN_W1_IDX 3 +-#define CN_W1_VAL 1 +- + enum w1_netlink_message_types { + W1_SLAVE_ADD = 0, + W1_SLAVE_REMOVE, +--- gregkh-2.6.orig/include/linux/connector.h ++++ gregkh-2.6/include/linux/connector.h +@@ -34,8 +34,11 @@ + #define CN_VAL_PROC 0x1 + #define CN_IDX_CIFS 0x2 + #define CN_VAL_CIFS 0x1 ++#define CN_W1_IDX 0x3 /* w1 communication */ ++#define CN_W1_VAL 0x1 + +-#define CN_NETLINK_USERS 1 ++ ++#define CN_NETLINK_USERS 4 + + /* + * Maximum connector's message size. diff --git a/i2c/w1-netlink-mark-netlink-group-1-as-unused.patch b/i2c/w1-netlink-mark-netlink-group-1-as-unused.patch new file mode 100644 index 0000000000000..b09b6d27a49b2 --- /dev/null +++ b/i2c/w1-netlink-mark-netlink-group-1-as-unused.patch @@ -0,0 +1,29 @@ +From johnpol@2ka.mipt.ru Thu Mar 23 08:00:20 2006 +Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Subject: [PATCH 5/5] w1: netlink: Mark netlink group 1 as unused. +Date: Thu, 23 Mar 2006 19:11:58 +0300 +Message-Id: <11431303183286@2ka.mipt.ru> +To: GregKH <greg@kroah.com> +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> + + +netlink_w1 was moved to connector. + +Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + include/linux/netlink.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- gregkh-2.6.orig/include/linux/netlink.h ++++ gregkh-2.6/include/linux/netlink.h +@@ -5,7 +5,7 @@ + #include <linux/types.h> + + #define NETLINK_ROUTE 0 /* Routing/device hook */ +-#define NETLINK_W1 1 /* 1-wire subsystem */ ++#define NETLINK_UNUSED 1 /* Unused number */ + #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ + #define NETLINK_FIREWALL 3 /* Firewalling hook */ + #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ diff --git a/i2c/w1-replace-dscore-and-ds_w1_bridge-with-ds2490-driver.patch b/i2c/w1-replace-dscore-and-ds_w1_bridge-with-ds2490-driver.patch new file mode 100644 index 0000000000000..ba266a9aa2205 --- /dev/null +++ b/i2c/w1-replace-dscore-and-ds_w1_bridge-with-ds2490-driver.patch @@ -0,0 +1,2185 @@ +From johnpol@2ka.mipt.ru Thu Mar 23 08:00:09 2006 +Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Subject: [PATCH 2/5] w1: Replace dscore and ds_w1_bridge with ds2490 driver. +Date: Thu, 23 Mar 2006 19:11:58 +0300 +Message-Id: <11431303181703@2ka.mipt.ru> +To: GregKH <greg@kroah.com> +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> + + +--- + Documentation/w1/masters/ds2490 | 18 + drivers/w1/masters/Kconfig | 27 - + drivers/w1/masters/Makefile | 7 + drivers/w1/masters/ds2490.c | 947 ++++++++++++++++++++++++++++++++++++++ + drivers/w1/masters/ds_w1_bridge.c | 174 ------ + drivers/w1/masters/dscore.c | 795 ------------------------------- + drivers/w1/masters/dscore.h | 166 ------ + 7 files changed, 975 insertions(+), 1159 deletions(-) + +--- /dev/null ++++ gregkh-2.6/Documentation/w1/masters/ds2490 +@@ -0,0 +1,18 @@ ++Kernel driver ds2490 ++==================== ++ ++Supported chips: ++ * Maxim DS2490 based ++ ++Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru> ++ ++ ++Description ++----------- ++ ++The Maixm/Dallas Semiconductor DS2490 is a chip ++which allows to build USB <-> W1 bridges. ++ ++DS9490(R) is a USB <-> W1 bus master device ++which has 0x81 family ID integrated chip and DS2490 ++low-level operational chip. +--- gregkh-2.6.orig/drivers/w1/masters/Kconfig ++++ gregkh-2.6/drivers/w1/masters/Kconfig +@@ -15,24 +15,15 @@ config W1_MASTER_MATROX + This support is also available as a module. If so, the module + will be called matrox_w1.ko. + +-config W1_MASTER_DS9490 +- tristate "DS9490R transport layer driver" +- depends on W1 && USB +- help +- Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. +- +- This support is also available as a module. If so, the module +- will be called ds9490r.ko. +- +-config W1_MASTER_DS9490_BRIDGE +- tristate "DS9490R USB <-> W1 transport layer for 1-wire" +- depends on W1_MASTER_DS9490 +- help +- Say Y here if you want to communicate with your 1-wire devices +- using DS9490R USB bridge. +- +- This support is also available as a module. If so, the module +- will be called ds_w1_bridge.ko. ++config W1_MASTER_DS2490 ++ tristate "DS2490 USB <-> W1 transport layer for 1-wire" ++ depends on W1 && USB ++ help ++ Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, ++ for example DS9490*. ++ ++ This support is also available as a module. If so, the module ++ will be called ds2490.ko. + + config W1_MASTER_DS2482 + tristate "Maxim DS2482 I2C to 1-Wire bridge" +--- gregkh-2.6.orig/drivers/w1/masters/Makefile ++++ gregkh-2.6/drivers/w1/masters/Makefile +@@ -3,11 +3,6 @@ + # + + obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o +- +-obj-$(CONFIG_W1_MASTER_DS9490) += ds9490r.o +-ds9490r-objs := dscore.o +- +-obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE) += ds_w1_bridge.o +- ++obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o + obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o + +--- /dev/null ++++ gregkh-2.6/drivers/w1/masters/ds2490.c +@@ -0,0 +1,947 @@ ++/* ++ * dscore.c ++ * ++ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> ++ * ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/mod_devicetable.h> ++#include <linux/usb.h> ++ ++#include "../w1_int.h" ++#include "../w1.h" ++ ++/* COMMAND TYPE CODES */ ++#define CONTROL_CMD 0x00 ++#define COMM_CMD 0x01 ++#define MODE_CMD 0x02 ++ ++/* CONTROL COMMAND CODES */ ++#define CTL_RESET_DEVICE 0x0000 ++#define CTL_START_EXE 0x0001 ++#define CTL_RESUME_EXE 0x0002 ++#define CTL_HALT_EXE_IDLE 0x0003 ++#define CTL_HALT_EXE_DONE 0x0004 ++#define CTL_FLUSH_COMM_CMDS 0x0007 ++#define CTL_FLUSH_RCV_BUFFER 0x0008 ++#define CTL_FLUSH_XMT_BUFFER 0x0009 ++#define CTL_GET_COMM_CMDS 0x000A ++ ++/* MODE COMMAND CODES */ ++#define MOD_PULSE_EN 0x0000 ++#define MOD_SPEED_CHANGE_EN 0x0001 ++#define MOD_1WIRE_SPEED 0x0002 ++#define MOD_STRONG_PU_DURATION 0x0003 ++#define MOD_PULLDOWN_SLEWRATE 0x0004 ++#define MOD_PROG_PULSE_DURATION 0x0005 ++#define MOD_WRITE1_LOWTIME 0x0006 ++#define MOD_DSOW0_TREC 0x0007 ++ ++/* COMMUNICATION COMMAND CODES */ ++#define COMM_ERROR_ESCAPE 0x0601 ++#define COMM_SET_DURATION 0x0012 ++#define COMM_BIT_IO 0x0020 ++#define COMM_PULSE 0x0030 ++#define COMM_1_WIRE_RESET 0x0042 ++#define COMM_BYTE_IO 0x0052 ++#define COMM_MATCH_ACCESS 0x0064 ++#define COMM_BLOCK_IO 0x0074 ++#define COMM_READ_STRAIGHT 0x0080 ++#define COMM_DO_RELEASE 0x6092 ++#define COMM_SET_PATH 0x00A2 ++#define COMM_WRITE_SRAM_PAGE 0x00B2 ++#define COMM_WRITE_EPROM 0x00C4 ++#define COMM_READ_CRC_PROT_PAGE 0x00D4 ++#define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 ++#define COMM_SEARCH_ACCESS 0x00F4 ++ ++/* Communication command bits */ ++#define COMM_TYPE 0x0008 ++#define COMM_SE 0x0008 ++#define COMM_D 0x0008 ++#define COMM_Z 0x0008 ++#define COMM_CH 0x0008 ++#define COMM_SM 0x0008 ++#define COMM_R 0x0008 ++#define COMM_IM 0x0001 ++ ++#define COMM_PS 0x4000 ++#define COMM_PST 0x4000 ++#define COMM_CIB 0x4000 ++#define COMM_RTS 0x4000 ++#define COMM_DT 0x2000 ++#define COMM_SPU 0x1000 ++#define COMM_F 0x0800 ++#define COMM_NTP 0x0400 ++#define COMM_ICP 0x0200 ++#define COMM_RST 0x0100 ++ ++#define PULSE_PROG 0x01 ++#define PULSE_SPUE 0x02 ++ ++#define BRANCH_MAIN 0xCC ++#define BRANCH_AUX 0x33 ++ ++/* ++ * Duration of the strong pull-up pulse in milliseconds. ++ */ ++#define PULLUP_PULSE_DURATION 750 ++ ++/* Status flags */ ++#define ST_SPUA 0x01 /* Strong Pull-up is active */ ++#define ST_PRGA 0x02 /* 12V programming pulse is being generated */ ++#define ST_12VP 0x04 /* external 12V programming voltage is present */ ++#define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ ++#define ST_HALT 0x10 /* DS2490 is currently halted */ ++#define ST_IDLE 0x20 /* DS2490 is currently idle */ ++#define ST_EPOF 0x80 ++ ++#define SPEED_NORMAL 0x00 ++#define SPEED_FLEXIBLE 0x01 ++#define SPEED_OVERDRIVE 0x02 ++ ++#define NUM_EP 4 ++#define EP_CONTROL 0 ++#define EP_STATUS 1 ++#define EP_DATA_OUT 2 ++#define EP_DATA_IN 3 ++ ++struct ds_device ++{ ++ struct list_head ds_entry; ++ ++ struct usb_device *udev; ++ struct usb_interface *intf; ++ ++ int ep[NUM_EP]; ++ ++ struct w1_bus_master master; ++}; ++ ++struct ds_status ++{ ++ u8 enable; ++ u8 speed; ++ u8 pullup_dur; ++ u8 ppuls_dur; ++ u8 pulldown_slew; ++ u8 write1_time; ++ u8 write0_time; ++ u8 reserved0; ++ u8 status; ++ u8 command0; ++ u8 command1; ++ u8 command_buffer_status; ++ u8 data_out_buffer_status; ++ u8 data_in_buffer_status; ++ u8 reserved1; ++ u8 reserved2; ++ ++}; ++ ++static struct usb_device_id ds_id_table [] = { ++ { USB_DEVICE(0x04fa, 0x2490) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(usb, ds_id_table); ++ ++static int ds_probe(struct usb_interface *, const struct usb_device_id *); ++static void ds_disconnect(struct usb_interface *); ++ ++static inline void ds_dump_status(unsigned char *, unsigned char *, int); ++static int ds_send_control(struct ds_device *, u16, u16); ++static int ds_send_control_cmd(struct ds_device *, u16, u16); ++ ++static LIST_HEAD(ds_devices); ++static DECLARE_MUTEX(ds_mutex); ++ ++static struct usb_driver ds_driver = { ++ .name = "DS9490R", ++ .probe = ds_probe, ++ .disconnect = ds_disconnect, ++ .id_table = ds_id_table, ++}; ++ ++static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) ++{ ++ int err; ++ ++ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), ++ CONTROL_CMD, 0x40, value, index, NULL, 0, 1000); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n", ++ value, index, err); ++ return err; ++ } ++ ++ return err; ++} ++#if 0 ++static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) ++{ ++ int err; ++ ++ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), ++ MODE_CMD, 0x40, value, index, NULL, 0, 1000); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n", ++ value, index, err); ++ return err; ++ } ++ ++ return err; ++} ++#endif ++static int ds_send_control(struct ds_device *dev, u16 value, u16 index) ++{ ++ int err; ++ ++ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), ++ COMM_CMD, 0x40, value, index, NULL, 0, 1000); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n", ++ value, index, err); ++ return err; ++ } ++ ++ return err; ++} ++ ++static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off) ++{ ++ printk("%45s: %8x\n", str, buf[off]); ++} ++ ++static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, ++ unsigned char *buf, int size) ++{ ++ int count, err; ++ ++ memset(st, 0, sizeof(st)); ++ ++ count = 0; ++ err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err); ++ return err; ++ } ++ ++ if (count >= sizeof(*st)) ++ memcpy(st, buf, sizeof(*st)); ++ ++ return count; ++} ++ ++static int ds_recv_status(struct ds_device *dev, struct ds_status *st) ++{ ++ unsigned char buf[64]; ++ int count, err = 0, i; ++ ++ memcpy(st, buf, sizeof(*st)); ++ ++ count = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); ++ if (count < 0) ++ return err; ++ ++ printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count); ++ for (i=0; i<count; ++i) ++ printk("%02x ", buf[i]); ++ printk("\n"); ++ ++ if (count >= 16) { ++ ds_dump_status(buf, "enable flag", 0); ++ ds_dump_status(buf, "1-wire speed", 1); ++ ds_dump_status(buf, "strong pullup duration", 2); ++ ds_dump_status(buf, "programming pulse duration", 3); ++ ds_dump_status(buf, "pulldown slew rate control", 4); ++ ds_dump_status(buf, "write-1 low time", 5); ++ ds_dump_status(buf, "data sample offset/write-0 recovery time", 6); ++ ds_dump_status(buf, "reserved (test register)", 7); ++ ds_dump_status(buf, "device status flags", 8); ++ ds_dump_status(buf, "communication command byte 1", 9); ++ ds_dump_status(buf, "communication command byte 2", 10); ++ ds_dump_status(buf, "communication command buffer status", 11); ++ ds_dump_status(buf, "1-wire data output buffer status", 12); ++ ds_dump_status(buf, "1-wire data input buffer status", 13); ++ ds_dump_status(buf, "reserved", 14); ++ ds_dump_status(buf, "reserved", 15); ++ } ++ ++ memcpy(st, buf, sizeof(*st)); ++ ++ if (st->status & ST_EPOF) { ++ printk(KERN_INFO "Resetting device after ST_EPOF.\n"); ++ err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0); ++ if (err) ++ return err; ++ count = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); ++ if (count < 0) ++ return err; ++ } ++#if 0 ++ if (st->status & ST_IDLE) { ++ printk(KERN_INFO "Resetting pulse after ST_IDLE.\n"); ++ err = ds_start_pulse(dev, PULLUP_PULSE_DURATION); ++ if (err) ++ return err; ++ } ++#endif ++ ++ return err; ++} ++ ++static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) ++{ ++ int count, err; ++ struct ds_status st; ++ ++ count = 0; ++ err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), ++ buf, size, &count, 1000); ++ if (err < 0) { ++ printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]); ++ usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN])); ++ ds_recv_status(dev, &st); ++ return err; ++ } ++ ++#if 0 ++ { ++ int i; ++ ++ printk("%s: count=%d: ", __func__, count); ++ for (i=0; i<count; ++i) ++ printk("%02x ", buf[i]); ++ printk("\n"); ++ } ++#endif ++ return count; ++} ++ ++static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len) ++{ ++ int count, err; ++ ++ count = 0; ++ err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++#if 0 ++ ++int ds_stop_pulse(struct ds_device *dev, int limit) ++{ ++ struct ds_status st; ++ int count = 0, err = 0; ++ u8 buf[0x20]; ++ ++ do { ++ err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0); ++ if (err) ++ break; ++ err = ds_send_control(dev, CTL_RESUME_EXE, 0); ++ if (err) ++ break; ++ err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf)); ++ if (err) ++ break; ++ ++ if ((st.status & ST_SPUA) == 0) { ++ err = ds_send_control_mode(dev, MOD_PULSE_EN, 0); ++ if (err) ++ break; ++ } ++ } while(++count < limit); ++ ++ return err; ++} ++ ++int ds_detect(struct ds_device *dev, struct ds_status *st) ++{ ++ int err; ++ ++ err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0); ++ if (err) ++ return err; ++ ++ err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0); ++ if (err) ++ return err; ++ ++ err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40); ++ if (err) ++ return err; ++ ++ err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG); ++ if (err) ++ return err; ++ ++ err = ds_recv_status(dev, st); ++ ++ return err; ++} ++ ++#endif /* 0 */ ++ ++static int ds_wait_status(struct ds_device *dev, struct ds_status *st) ++{ ++ u8 buf[0x20]; ++ int err, count = 0; ++ ++ do { ++ err = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); ++#if 0 ++ if (err >= 0) { ++ int i; ++ printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err); ++ for (i=0; i<err; ++i) ++ printk("%02x ", buf[i]); ++ printk("\n"); ++ } ++#endif ++ } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100); ++ ++ ++ if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) { ++ ds_recv_status(dev, st); ++ return -1; ++ } else ++ return 0; ++} ++ ++static int ds_reset(struct ds_device *dev, struct ds_status *st) ++{ ++ int err; ++ ++ //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE); ++ err = ds_send_control(dev, 0x43, SPEED_NORMAL); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, st); ++#if 0 ++ if (st->command_buffer_status) { ++ printk(KERN_INFO "Short circuit.\n"); ++ return -EIO; ++ } ++#endif ++ ++ return 0; ++} ++ ++#if 0 ++static int ds_set_speed(struct ds_device *dev, int speed) ++{ ++ int err; ++ ++ if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE) ++ return -EINVAL; ++ ++ if (speed != SPEED_OVERDRIVE) ++ speed = SPEED_FLEXIBLE; ++ ++ speed &= 0xff; ++ ++ err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed); ++ if (err) ++ return err; ++ ++ return err; ++} ++#endif /* 0 */ ++ ++static int ds_start_pulse(struct ds_device *dev, int delay) ++{ ++ int err; ++ u8 del = 1 + (u8)(delay >> 4); ++ struct ds_status st; ++ ++#if 0 ++ err = ds_stop_pulse(dev, 10); ++ if (err) ++ return err; ++ ++ err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); ++ if (err) ++ return err; ++#endif ++ err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del); ++ if (err) ++ return err; ++ ++ err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0); ++ if (err) ++ return err; ++ ++ mdelay(delay); ++ ++ ds_wait_status(dev, &st); ++ ++ return err; ++} ++ ++static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) ++{ ++ int err, count; ++ struct ds_status st; ++ u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0); ++ u16 cmd; ++ ++ err = ds_send_control(dev, value, 0); ++ if (err) ++ return err; ++ ++ count = 0; ++ do { ++ err = ds_wait_status(dev, &st); ++ if (err) ++ return err; ++ ++ cmd = st.command0 | (st.command1 << 8); ++ } while (cmd != value && ++count < 10); ++ ++ if (err < 0 || count >= 10) { ++ printk(KERN_ERR "Failed to obtain status.\n"); ++ return -EINVAL; ++ } ++ ++ err = ds_recv_data(dev, tbit, sizeof(*tbit)); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int ds_write_bit(struct ds_device *dev, u8 bit) ++{ ++ int err; ++ struct ds_status st; ++ ++ err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ return 0; ++} ++ ++static int ds_write_byte(struct ds_device *dev, u8 byte) ++{ ++ int err; ++ struct ds_status st; ++ u8 rbyte; ++ ++ err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte); ++ if (err) ++ return err; ++ ++ err = ds_wait_status(dev, &st); ++ if (err) ++ return err; ++ ++ err = ds_recv_data(dev, &rbyte, sizeof(rbyte)); ++ if (err < 0) ++ return err; ++ ++ ds_start_pulse(dev, PULLUP_PULSE_DURATION); ++ ++ return !(byte == rbyte); ++} ++ ++static int ds_read_byte(struct ds_device *dev, u8 *byte) ++{ ++ int err; ++ struct ds_status st; ++ ++ err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ err = ds_recv_data(dev, byte, sizeof(*byte)); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int ds_read_block(struct ds_device *dev, u8 *buf, int len) ++{ ++ struct ds_status st; ++ int err; ++ ++ if (len > 64*1024) ++ return -E2BIG; ++ ++ memset(buf, 0xFF, len); ++ ++ err = ds_send_data(dev, buf, len); ++ if (err < 0) ++ return err; ++ ++ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ memset(buf, 0x00, len); ++ err = ds_recv_data(dev, buf, len); ++ ++ return err; ++} ++ ++static int ds_write_block(struct ds_device *dev, u8 *buf, int len) ++{ ++ int err; ++ struct ds_status st; ++ ++ err = ds_send_data(dev, buf, len); ++ if (err < 0) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ err = ds_recv_data(dev, buf, len); ++ if (err < 0) ++ return err; ++ ++ ds_start_pulse(dev, PULLUP_PULSE_DURATION); ++ ++ return !(err == len); ++} ++ ++#if 0 ++ ++static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) ++{ ++ int err; ++ u16 value, index; ++ struct ds_status st; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ err = ds_send_data(ds_dev, (unsigned char *)&init, 8); ++ if (err) ++ return err; ++ ++ ds_wait_status(ds_dev, &st); ++ ++ value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS; ++ index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8); ++ err = ds_send_control(ds_dev, value, index); ++ if (err) ++ return err; ++ ++ ds_wait_status(ds_dev, &st); ++ ++ err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number); ++ if (err < 0) ++ return err; ++ ++ return err/8; ++} ++ ++static int ds_match_access(struct ds_device *dev, u64 init) ++{ ++ int err; ++ struct ds_status st; ++ ++ err = ds_send_data(dev, (unsigned char *)&init, sizeof(init)); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ return 0; ++} ++ ++static int ds_set_path(struct ds_device *dev, u64 init) ++{ ++ int err; ++ struct ds_status st; ++ u8 buf[9]; ++ ++ memcpy(buf, &init, 8); ++ buf[8] = BRANCH_MAIN; ++ ++ err = ds_send_data(dev, buf, sizeof(buf)); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0); ++ if (err) ++ return err; ++ ++ ds_wait_status(dev, &st); ++ ++ return 0; ++} ++ ++#endif /* 0 */ ++ ++static u8 ds9490r_touch_bit(void *data, u8 bit) ++{ ++ u8 ret; ++ struct ds_device *dev = data; ++ ++ if (ds_touch_bit(dev, bit, &ret)) ++ return 0; ++ ++ return ret; ++} ++ ++static void ds9490r_write_bit(void *data, u8 bit) ++{ ++ struct ds_device *dev = data; ++ ++ ds_write_bit(dev, bit); ++} ++ ++static void ds9490r_write_byte(void *data, u8 byte) ++{ ++ struct ds_device *dev = data; ++ ++ ds_write_byte(dev, byte); ++} ++ ++static u8 ds9490r_read_bit(void *data) ++{ ++ struct ds_device *dev = data; ++ int err; ++ u8 bit = 0; ++ ++ err = ds_touch_bit(dev, 1, &bit); ++ if (err) ++ return 0; ++ ++ return bit & 1; ++} ++ ++static u8 ds9490r_read_byte(void *data) ++{ ++ struct ds_device *dev = data; ++ int err; ++ u8 byte = 0; ++ ++ err = ds_read_byte(dev, &byte); ++ if (err) ++ return 0; ++ ++ return byte; ++} ++ ++static void ds9490r_write_block(void *data, const u8 *buf, int len) ++{ ++ struct ds_device *dev = data; ++ ++ ds_write_block(dev, (u8 *)buf, len); ++} ++ ++static u8 ds9490r_read_block(void *data, u8 *buf, int len) ++{ ++ struct ds_device *dev = data; ++ int err; ++ ++ err = ds_read_block(dev, buf, len); ++ if (err < 0) ++ return 0; ++ ++ return len; ++} ++ ++static u8 ds9490r_reset(void *data) ++{ ++ struct ds_device *dev = data; ++ struct ds_status st; ++ int err; ++ ++ memset(&st, 0, sizeof(st)); ++ ++ err = ds_reset(dev, &st); ++ if (err) ++ return 1; ++ ++ return 0; ++} ++ ++static int ds_w1_init(struct ds_device *dev) ++{ ++ memset(&dev->master, 0, sizeof(struct w1_bus_master)); ++ ++ dev->master.data = dev; ++ dev->master.touch_bit = &ds9490r_touch_bit; ++ dev->master.read_bit = &ds9490r_read_bit; ++ dev->master.write_bit = &ds9490r_write_bit; ++ dev->master.read_byte = &ds9490r_read_byte; ++ dev->master.write_byte = &ds9490r_write_byte; ++ dev->master.read_block = &ds9490r_read_block; ++ dev->master.write_block = &ds9490r_write_block; ++ dev->master.reset_bus = &ds9490r_reset; ++ ++ return w1_add_master_device(&dev->master); ++} ++ ++static void ds_w1_fini(struct ds_device *dev) ++{ ++ w1_remove_master_device(&dev->master); ++} ++ ++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_endpoint_descriptor *endpoint; ++ struct usb_host_interface *iface_desc; ++ struct ds_device *dev; ++ int i, err; ++ ++ dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); ++ if (!dev) { ++ printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); ++ return -ENOMEM; ++ } ++ dev->udev = usb_get_dev(udev); ++ if (!dev->udev) { ++ err = -ENOMEM; ++ goto err_out_free; ++ } ++ memset(dev->ep, 0, sizeof(dev->ep)); ++ ++ usb_set_intfdata(intf, dev); ++ ++ err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); ++ if (err) { ++ printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", ++ intf->altsetting[0].desc.bInterfaceNumber, err); ++ goto err_out_clear; ++ } ++ ++ err = usb_reset_configuration(dev->udev); ++ if (err) { ++ printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); ++ goto err_out_clear; ++ } ++ ++ iface_desc = &intf->altsetting[0]; ++ if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { ++ printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); ++ err = -EINVAL; ++ goto err_out_clear; ++ } ++ ++ /* ++ * This loop doesn'd show control 0 endpoint, ++ * so we will fill only 1-3 endpoints entry. ++ */ ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { ++ endpoint = &iface_desc->endpoint[i].desc; ++ ++ dev->ep[i+1] = endpoint->bEndpointAddress; ++#if 0 ++ printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", ++ i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), ++ (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", ++ endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); ++#endif ++ } ++ ++ err = ds_w1_init(dev); ++ if (err) ++ goto err_out_clear; ++ ++ down(&ds_mutex); ++ list_add_tail(&dev->ds_entry, &ds_devices); ++ up(&ds_mutex); ++ ++ return 0; ++ ++err_out_clear: ++ usb_set_intfdata(intf, NULL); ++ usb_put_dev(dev->udev); ++err_out_free: ++ kfree(dev); ++ return err; ++} ++ ++static void ds_disconnect(struct usb_interface *intf) ++{ ++ struct ds_device *dev; ++ ++ dev = usb_get_intfdata(intf); ++ if (!dev) ++ return; ++ ++ down(&ds_mutex); ++ list_del(&dev->ds_entry); ++ up(&ds_mutex); ++ ++ ds_w1_fini(dev); ++ ++ usb_set_intfdata(intf, NULL); ++ ++ usb_put_dev(dev->udev); ++ kfree(dev); ++} ++ ++static int ds_init(void) ++{ ++ int err; ++ ++ err = usb_register(&ds_driver); ++ if (err) { ++ printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void ds_fini(void) ++{ ++ usb_deregister(&ds_driver); ++} ++ ++module_init(ds_init); ++module_exit(ds_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); ++MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)"); +--- gregkh-2.6.orig/drivers/w1/masters/ds_w1_bridge.c ++++ /dev/null +@@ -1,174 +0,0 @@ +-/* +- * ds_w1_bridge.c +- * +- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> +- * +- * +- * 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 +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/module.h> +-#include <linux/types.h> +- +-#include "../w1.h" +-#include "../w1_int.h" +-#include "dscore.h" +- +-static struct ds_device *ds_dev; +-static struct w1_bus_master *ds_bus_master; +- +-static u8 ds9490r_touch_bit(void *data, u8 bit) +-{ +- u8 ret; +- struct ds_device *dev = data; +- +- if (ds_touch_bit(dev, bit, &ret)) +- return 0; +- +- return ret; +-} +- +-static void ds9490r_write_bit(void *data, u8 bit) +-{ +- struct ds_device *dev = data; +- +- ds_write_bit(dev, bit); +-} +- +-static void ds9490r_write_byte(void *data, u8 byte) +-{ +- struct ds_device *dev = data; +- +- ds_write_byte(dev, byte); +-} +- +-static u8 ds9490r_read_bit(void *data) +-{ +- struct ds_device *dev = data; +- int err; +- u8 bit = 0; +- +- err = ds_touch_bit(dev, 1, &bit); +- if (err) +- return 0; +- //err = ds_read_bit(dev, &bit); +- //if (err) +- // return 0; +- +- return bit & 1; +-} +- +-static u8 ds9490r_read_byte(void *data) +-{ +- struct ds_device *dev = data; +- int err; +- u8 byte = 0; +- +- err = ds_read_byte(dev, &byte); +- if (err) +- return 0; +- +- return byte; +-} +- +-static void ds9490r_write_block(void *data, const u8 *buf, int len) +-{ +- struct ds_device *dev = data; +- +- ds_write_block(dev, (u8 *)buf, len); +-} +- +-static u8 ds9490r_read_block(void *data, u8 *buf, int len) +-{ +- struct ds_device *dev = data; +- int err; +- +- err = ds_read_block(dev, buf, len); +- if (err < 0) +- return 0; +- +- return len; +-} +- +-static u8 ds9490r_reset(void *data) +-{ +- struct ds_device *dev = data; +- struct ds_status st; +- int err; +- +- memset(&st, 0, sizeof(st)); +- +- err = ds_reset(dev, &st); +- if (err) +- return 1; +- +- return 0; +-} +- +-static int __devinit ds_w1_init(void) +-{ +- int err; +- +- ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL); +- if (!ds_bus_master) { +- printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n"); +- return -ENOMEM; +- } +- +- ds_dev = ds_get_device(); +- if (!ds_dev) { +- printk(KERN_ERR "DS9490R is not registered.\n"); +- err = -ENODEV; +- goto err_out_free_bus_master; +- } +- +- memset(ds_bus_master, 0, sizeof(*ds_bus_master)); +- +- ds_bus_master->data = ds_dev; +- ds_bus_master->touch_bit = &ds9490r_touch_bit; +- ds_bus_master->read_bit = &ds9490r_read_bit; +- ds_bus_master->write_bit = &ds9490r_write_bit; +- ds_bus_master->read_byte = &ds9490r_read_byte; +- ds_bus_master->write_byte = &ds9490r_write_byte; +- ds_bus_master->read_block = &ds9490r_read_block; +- ds_bus_master->write_block = &ds9490r_write_block; +- ds_bus_master->reset_bus = &ds9490r_reset; +- +- err = w1_add_master_device(ds_bus_master); +- if (err) +- goto err_out_put_device; +- +- return 0; +- +-err_out_put_device: +- ds_put_device(ds_dev); +-err_out_free_bus_master: +- kfree(ds_bus_master); +- +- return err; +-} +- +-static void __devexit ds_w1_fini(void) +-{ +- w1_remove_master_device(ds_bus_master); +- ds_put_device(ds_dev); +- kfree(ds_bus_master); +-} +- +-module_init(ds_w1_init); +-module_exit(ds_w1_fini); +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +--- gregkh-2.6.orig/drivers/w1/masters/dscore.c ++++ /dev/null +@@ -1,795 +0,0 @@ +-/* +- * dscore.c +- * +- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> +- * +- * +- * 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 +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/module.h> +-#include <linux/kernel.h> +-#include <linux/mod_devicetable.h> +-#include <linux/usb.h> +- +-#include "dscore.h" +- +-static struct usb_device_id ds_id_table [] = { +- { USB_DEVICE(0x04fa, 0x2490) }, +- { }, +-}; +-MODULE_DEVICE_TABLE(usb, ds_id_table); +- +-static int ds_probe(struct usb_interface *, const struct usb_device_id *); +-static void ds_disconnect(struct usb_interface *); +- +-int ds_touch_bit(struct ds_device *, u8, u8 *); +-int ds_read_byte(struct ds_device *, u8 *); +-int ds_read_bit(struct ds_device *, u8 *); +-int ds_write_byte(struct ds_device *, u8); +-int ds_write_bit(struct ds_device *, u8); +-static int ds_start_pulse(struct ds_device *, int); +-int ds_reset(struct ds_device *, struct ds_status *); +-struct ds_device * ds_get_device(void); +-void ds_put_device(struct ds_device *); +- +-static inline void ds_dump_status(unsigned char *, unsigned char *, int); +-static int ds_send_control(struct ds_device *, u16, u16); +-static int ds_send_control_mode(struct ds_device *, u16, u16); +-static int ds_send_control_cmd(struct ds_device *, u16, u16); +- +- +-static struct usb_driver ds_driver = { +- .name = "DS9490R", +- .probe = ds_probe, +- .disconnect = ds_disconnect, +- .id_table = ds_id_table, +-}; +- +-static struct ds_device *ds_dev; +- +-struct ds_device * ds_get_device(void) +-{ +- if (ds_dev) +- atomic_inc(&ds_dev->refcnt); +- return ds_dev; +-} +- +-void ds_put_device(struct ds_device *dev) +-{ +- atomic_dec(&dev->refcnt); +-} +- +-static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) +-{ +- int err; +- +- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), +- CONTROL_CMD, 0x40, value, index, NULL, 0, 1000); +- if (err < 0) { +- printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n", +- value, index, err); +- return err; +- } +- +- return err; +-} +- +-static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) +-{ +- int err; +- +- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), +- MODE_CMD, 0x40, value, index, NULL, 0, 1000); +- if (err < 0) { +- printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n", +- value, index, err); +- return err; +- } +- +- return err; +-} +- +-static int ds_send_control(struct ds_device *dev, u16 value, u16 index) +-{ +- int err; +- +- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), +- COMM_CMD, 0x40, value, index, NULL, 0, 1000); +- if (err < 0) { +- printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n", +- value, index, err); +- return err; +- } +- +- return err; +-} +- +-static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off) +-{ +- printk("%45s: %8x\n", str, buf[off]); +-} +- +-static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, +- unsigned char *buf, int size) +-{ +- int count, err; +- +- memset(st, 0, sizeof(st)); +- +- count = 0; +- err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100); +- if (err < 0) { +- printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err); +- return err; +- } +- +- if (count >= sizeof(*st)) +- memcpy(st, buf, sizeof(*st)); +- +- return count; +-} +- +-static int ds_recv_status(struct ds_device *dev, struct ds_status *st) +-{ +- unsigned char buf[64]; +- int count, err = 0, i; +- +- memcpy(st, buf, sizeof(*st)); +- +- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); +- if (count < 0) +- return err; +- +- printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count); +- for (i=0; i<count; ++i) +- printk("%02x ", buf[i]); +- printk("\n"); +- +- if (count >= 16) { +- ds_dump_status(buf, "enable flag", 0); +- ds_dump_status(buf, "1-wire speed", 1); +- ds_dump_status(buf, "strong pullup duration", 2); +- ds_dump_status(buf, "programming pulse duration", 3); +- ds_dump_status(buf, "pulldown slew rate control", 4); +- ds_dump_status(buf, "write-1 low time", 5); +- ds_dump_status(buf, "data sample offset/write-0 recovery time", 6); +- ds_dump_status(buf, "reserved (test register)", 7); +- ds_dump_status(buf, "device status flags", 8); +- ds_dump_status(buf, "communication command byte 1", 9); +- ds_dump_status(buf, "communication command byte 2", 10); +- ds_dump_status(buf, "communication command buffer status", 11); +- ds_dump_status(buf, "1-wire data output buffer status", 12); +- ds_dump_status(buf, "1-wire data input buffer status", 13); +- ds_dump_status(buf, "reserved", 14); +- ds_dump_status(buf, "reserved", 15); +- } +- +- memcpy(st, buf, sizeof(*st)); +- +- if (st->status & ST_EPOF) { +- printk(KERN_INFO "Resetting device after ST_EPOF.\n"); +- err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0); +- if (err) +- return err; +- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); +- if (count < 0) +- return err; +- } +-#if 0 +- if (st->status & ST_IDLE) { +- printk(KERN_INFO "Resetting pulse after ST_IDLE.\n"); +- err = ds_start_pulse(dev, PULLUP_PULSE_DURATION); +- if (err) +- return err; +- } +-#endif +- +- return err; +-} +- +-static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) +-{ +- int count, err; +- struct ds_status st; +- +- count = 0; +- err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), +- buf, size, &count, 1000); +- if (err < 0) { +- printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]); +- usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN])); +- ds_recv_status(dev, &st); +- return err; +- } +- +-#if 0 +- { +- int i; +- +- printk("%s: count=%d: ", __func__, count); +- for (i=0; i<count; ++i) +- printk("%02x ", buf[i]); +- printk("\n"); +- } +-#endif +- return count; +-} +- +-static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len) +-{ +- int count, err; +- +- count = 0; +- err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000); +- if (err < 0) { +- printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err); +- return err; +- } +- +- return err; +-} +- +-#if 0 +- +-int ds_stop_pulse(struct ds_device *dev, int limit) +-{ +- struct ds_status st; +- int count = 0, err = 0; +- u8 buf[0x20]; +- +- do { +- err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0); +- if (err) +- break; +- err = ds_send_control(dev, CTL_RESUME_EXE, 0); +- if (err) +- break; +- err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf)); +- if (err) +- break; +- +- if ((st.status & ST_SPUA) == 0) { +- err = ds_send_control_mode(dev, MOD_PULSE_EN, 0); +- if (err) +- break; +- } +- } while(++count < limit); +- +- return err; +-} +- +-int ds_detect(struct ds_device *dev, struct ds_status *st) +-{ +- int err; +- +- err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0); +- if (err) +- return err; +- +- err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0); +- if (err) +- return err; +- +- err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40); +- if (err) +- return err; +- +- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG); +- if (err) +- return err; +- +- err = ds_recv_status(dev, st); +- +- return err; +-} +- +-#endif /* 0 */ +- +-static int ds_wait_status(struct ds_device *dev, struct ds_status *st) +-{ +- u8 buf[0x20]; +- int err, count = 0; +- +- do { +- err = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); +-#if 0 +- if (err >= 0) { +- int i; +- printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err); +- for (i=0; i<err; ++i) +- printk("%02x ", buf[i]); +- printk("\n"); +- } +-#endif +- } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100); +- +- +- if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) { +- ds_recv_status(dev, st); +- return -1; +- } else +- return 0; +-} +- +-int ds_reset(struct ds_device *dev, struct ds_status *st) +-{ +- int err; +- +- //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE); +- err = ds_send_control(dev, 0x43, SPEED_NORMAL); +- if (err) +- return err; +- +- ds_wait_status(dev, st); +-#if 0 +- if (st->command_buffer_status) { +- printk(KERN_INFO "Short circuit.\n"); +- return -EIO; +- } +-#endif +- +- return 0; +-} +- +-#if 0 +-int ds_set_speed(struct ds_device *dev, int speed) +-{ +- int err; +- +- if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE) +- return -EINVAL; +- +- if (speed != SPEED_OVERDRIVE) +- speed = SPEED_FLEXIBLE; +- +- speed &= 0xff; +- +- err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed); +- if (err) +- return err; +- +- return err; +-} +-#endif /* 0 */ +- +-static int ds_start_pulse(struct ds_device *dev, int delay) +-{ +- int err; +- u8 del = 1 + (u8)(delay >> 4); +- struct ds_status st; +- +-#if 0 +- err = ds_stop_pulse(dev, 10); +- if (err) +- return err; +- +- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); +- if (err) +- return err; +-#endif +- err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del); +- if (err) +- return err; +- +- err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0); +- if (err) +- return err; +- +- mdelay(delay); +- +- ds_wait_status(dev, &st); +- +- return err; +-} +- +-int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) +-{ +- int err, count; +- struct ds_status st; +- u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0); +- u16 cmd; +- +- err = ds_send_control(dev, value, 0); +- if (err) +- return err; +- +- count = 0; +- do { +- err = ds_wait_status(dev, &st); +- if (err) +- return err; +- +- cmd = st.command0 | (st.command1 << 8); +- } while (cmd != value && ++count < 10); +- +- if (err < 0 || count >= 10) { +- printk(KERN_ERR "Failed to obtain status.\n"); +- return -EINVAL; +- } +- +- err = ds_recv_data(dev, tbit, sizeof(*tbit)); +- if (err < 0) +- return err; +- +- return 0; +-} +- +-int ds_write_bit(struct ds_device *dev, u8 bit) +-{ +- int err; +- struct ds_status st; +- +- err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- return 0; +-} +- +-int ds_write_byte(struct ds_device *dev, u8 byte) +-{ +- int err; +- struct ds_status st; +- u8 rbyte; +- +- err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte); +- if (err) +- return err; +- +- err = ds_wait_status(dev, &st); +- if (err) +- return err; +- +- err = ds_recv_data(dev, &rbyte, sizeof(rbyte)); +- if (err < 0) +- return err; +- +- ds_start_pulse(dev, PULLUP_PULSE_DURATION); +- +- return !(byte == rbyte); +-} +- +-int ds_read_bit(struct ds_device *dev, u8 *bit) +-{ +- int err; +- +- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); +- if (err) +- return err; +- +- err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0); +- if (err) +- return err; +- +- err = ds_recv_data(dev, bit, sizeof(*bit)); +- if (err < 0) +- return err; +- +- return 0; +-} +- +-int ds_read_byte(struct ds_device *dev, u8 *byte) +-{ +- int err; +- struct ds_status st; +- +- err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- err = ds_recv_data(dev, byte, sizeof(*byte)); +- if (err < 0) +- return err; +- +- return 0; +-} +- +-int ds_read_block(struct ds_device *dev, u8 *buf, int len) +-{ +- struct ds_status st; +- int err; +- +- if (len > 64*1024) +- return -E2BIG; +- +- memset(buf, 0xFF, len); +- +- err = ds_send_data(dev, buf, len); +- if (err < 0) +- return err; +- +- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- memset(buf, 0x00, len); +- err = ds_recv_data(dev, buf, len); +- +- return err; +-} +- +-int ds_write_block(struct ds_device *dev, u8 *buf, int len) +-{ +- int err; +- struct ds_status st; +- +- err = ds_send_data(dev, buf, len); +- if (err < 0) +- return err; +- +- ds_wait_status(dev, &st); +- +- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- err = ds_recv_data(dev, buf, len); +- if (err < 0) +- return err; +- +- ds_start_pulse(dev, PULLUP_PULSE_DURATION); +- +- return !(err == len); +-} +- +-#if 0 +- +-int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) +-{ +- int err; +- u16 value, index; +- struct ds_status st; +- +- memset(buf, 0, sizeof(buf)); +- +- err = ds_send_data(ds_dev, (unsigned char *)&init, 8); +- if (err) +- return err; +- +- ds_wait_status(ds_dev, &st); +- +- value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS; +- index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8); +- err = ds_send_control(ds_dev, value, index); +- if (err) +- return err; +- +- ds_wait_status(ds_dev, &st); +- +- err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number); +- if (err < 0) +- return err; +- +- return err/8; +-} +- +-int ds_match_access(struct ds_device *dev, u64 init) +-{ +- int err; +- struct ds_status st; +- +- err = ds_send_data(dev, (unsigned char *)&init, sizeof(init)); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- return 0; +-} +- +-int ds_set_path(struct ds_device *dev, u64 init) +-{ +- int err; +- struct ds_status st; +- u8 buf[9]; +- +- memcpy(buf, &init, 8); +- buf[8] = BRANCH_MAIN; +- +- err = ds_send_data(dev, buf, sizeof(buf)); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0); +- if (err) +- return err; +- +- ds_wait_status(dev, &st); +- +- return 0; +-} +- +-#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_endpoint_descriptor *endpoint; +- struct usb_host_interface *iface_desc; +- int i, err; +- +- ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); +- if (!ds_dev) { +- printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); +- return -ENOMEM; +- } +- +- ds_dev->udev = usb_get_dev(udev); +- usb_set_intfdata(intf, ds_dev); +- +- err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); +- if (err) { +- printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", +- intf->altsetting[0].desc.bInterfaceNumber, err); +- return err; +- } +- +- err = usb_reset_configuration(ds_dev->udev); +- if (err) { +- printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); +- return err; +- } +- +- iface_desc = &intf->altsetting[0]; +- if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { +- printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); +- return -ENODEV; +- } +- +- atomic_set(&ds_dev->refcnt, 0); +- memset(ds_dev->ep, 0, sizeof(ds_dev->ep)); +- +- /* +- * This loop doesn'd show control 0 endpoint, +- * so we will fill only 1-3 endpoints entry. +- */ +- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { +- endpoint = &iface_desc->endpoint[i].desc; +- +- ds_dev->ep[i+1] = endpoint->bEndpointAddress; +- +- printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", +- i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), +- (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", +- endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); +- } +- +-#if 0 +- { +- int err, i; +- u64 buf[3]; +- u64 init=0xb30000002078ee81ull; +- struct ds_status st; +- +- ds_reset(ds_dev, &st); +- err = ds_search(ds_dev, init, buf, 3, 0); +- if (err < 0) +- return err; +- for (i=0; i<err; ++i) +- printk("%d: %llx\n", i, buf[i]); +- +- printk("Resetting...\n"); +- ds_reset(ds_dev, &st); +- printk("Setting path for %llx.\n", init); +- err = ds_set_path(ds_dev, init); +- if (err) +- return err; +- printk("Calling MATCH_ACCESS.\n"); +- err = ds_match_access(ds_dev, init); +- if (err) +- return err; +- +- printk("Searching the bus...\n"); +- err = ds_search(ds_dev, init, buf, 3, 0); +- +- printk("ds_search() returned %d\n", err); +- +- if (err < 0) +- return err; +- for (i=0; i<err; ++i) +- printk("%d: %llx\n", i, buf[i]); +- +- return 0; +- } +-#endif +- +- return 0; +-} +- +-static void ds_disconnect(struct usb_interface *intf) +-{ +- struct ds_device *dev; +- +- dev = usb_get_intfdata(intf); +- usb_set_intfdata(intf, NULL); +- +- while (atomic_read(&dev->refcnt)) { +- printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n", +- atomic_read(&dev->refcnt)); +- +- if (msleep_interruptible(1000)) +- flush_signals(current); +- } +- +- usb_put_dev(dev->udev); +- kfree(dev); +- ds_dev = NULL; +-} +- +-static int ds_init(void) +-{ +- int err; +- +- err = usb_register(&ds_driver); +- if (err) { +- printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err); +- return err; +- } +- +- return 0; +-} +- +-static void ds_fini(void) +-{ +- usb_deregister(&ds_driver); +-} +- +-module_init(ds_init); +-module_exit(ds_fini); +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +- +-EXPORT_SYMBOL(ds_touch_bit); +-EXPORT_SYMBOL(ds_read_byte); +-EXPORT_SYMBOL(ds_read_bit); +-EXPORT_SYMBOL(ds_read_block); +-EXPORT_SYMBOL(ds_write_byte); +-EXPORT_SYMBOL(ds_write_bit); +-EXPORT_SYMBOL(ds_write_block); +-EXPORT_SYMBOL(ds_reset); +-EXPORT_SYMBOL(ds_get_device); +-EXPORT_SYMBOL(ds_put_device); +- +-/* +- * This functions can be used for EEPROM programming, +- * when driver will be included into mainline this will +- * require uncommenting. +- */ +-#if 0 +-EXPORT_SYMBOL(ds_start_pulse); +-EXPORT_SYMBOL(ds_set_speed); +-EXPORT_SYMBOL(ds_detect); +-EXPORT_SYMBOL(ds_stop_pulse); +-EXPORT_SYMBOL(ds_search); +-#endif +--- gregkh-2.6.orig/drivers/w1/masters/dscore.h ++++ /dev/null +@@ -1,166 +0,0 @@ +-/* +- * dscore.h +- * +- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> +- * +- * +- * 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 +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#ifndef __DSCORE_H +-#define __DSCORE_H +- +-#include <linux/usb.h> +-#include <asm/atomic.h> +- +-/* COMMAND TYPE CODES */ +-#define CONTROL_CMD 0x00 +-#define COMM_CMD 0x01 +-#define MODE_CMD 0x02 +- +-/* CONTROL COMMAND CODES */ +-#define CTL_RESET_DEVICE 0x0000 +-#define CTL_START_EXE 0x0001 +-#define CTL_RESUME_EXE 0x0002 +-#define CTL_HALT_EXE_IDLE 0x0003 +-#define CTL_HALT_EXE_DONE 0x0004 +-#define CTL_FLUSH_COMM_CMDS 0x0007 +-#define CTL_FLUSH_RCV_BUFFER 0x0008 +-#define CTL_FLUSH_XMT_BUFFER 0x0009 +-#define CTL_GET_COMM_CMDS 0x000A +- +-/* MODE COMMAND CODES */ +-#define MOD_PULSE_EN 0x0000 +-#define MOD_SPEED_CHANGE_EN 0x0001 +-#define MOD_1WIRE_SPEED 0x0002 +-#define MOD_STRONG_PU_DURATION 0x0003 +-#define MOD_PULLDOWN_SLEWRATE 0x0004 +-#define MOD_PROG_PULSE_DURATION 0x0005 +-#define MOD_WRITE1_LOWTIME 0x0006 +-#define MOD_DSOW0_TREC 0x0007 +- +-/* COMMUNICATION COMMAND CODES */ +-#define COMM_ERROR_ESCAPE 0x0601 +-#define COMM_SET_DURATION 0x0012 +-#define COMM_BIT_IO 0x0020 +-#define COMM_PULSE 0x0030 +-#define COMM_1_WIRE_RESET 0x0042 +-#define COMM_BYTE_IO 0x0052 +-#define COMM_MATCH_ACCESS 0x0064 +-#define COMM_BLOCK_IO 0x0074 +-#define COMM_READ_STRAIGHT 0x0080 +-#define COMM_DO_RELEASE 0x6092 +-#define COMM_SET_PATH 0x00A2 +-#define COMM_WRITE_SRAM_PAGE 0x00B2 +-#define COMM_WRITE_EPROM 0x00C4 +-#define COMM_READ_CRC_PROT_PAGE 0x00D4 +-#define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 +-#define COMM_SEARCH_ACCESS 0x00F4 +- +-/* Communication command bits */ +-#define COMM_TYPE 0x0008 +-#define COMM_SE 0x0008 +-#define COMM_D 0x0008 +-#define COMM_Z 0x0008 +-#define COMM_CH 0x0008 +-#define COMM_SM 0x0008 +-#define COMM_R 0x0008 +-#define COMM_IM 0x0001 +- +-#define COMM_PS 0x4000 +-#define COMM_PST 0x4000 +-#define COMM_CIB 0x4000 +-#define COMM_RTS 0x4000 +-#define COMM_DT 0x2000 +-#define COMM_SPU 0x1000 +-#define COMM_F 0x0800 +-#define COMM_NTP 0x0400 +-#define COMM_ICP 0x0200 +-#define COMM_RST 0x0100 +- +-#define PULSE_PROG 0x01 +-#define PULSE_SPUE 0x02 +- +-#define BRANCH_MAIN 0xCC +-#define BRANCH_AUX 0x33 +- +-/* +- * Duration of the strong pull-up pulse in milliseconds. +- */ +-#define PULLUP_PULSE_DURATION 750 +- +-/* Status flags */ +-#define ST_SPUA 0x01 /* Strong Pull-up is active */ +-#define ST_PRGA 0x02 /* 12V programming pulse is being generated */ +-#define ST_12VP 0x04 /* external 12V programming voltage is present */ +-#define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ +-#define ST_HALT 0x10 /* DS2490 is currently halted */ +-#define ST_IDLE 0x20 /* DS2490 is currently idle */ +-#define ST_EPOF 0x80 +- +-#define SPEED_NORMAL 0x00 +-#define SPEED_FLEXIBLE 0x01 +-#define SPEED_OVERDRIVE 0x02 +- +-#define NUM_EP 4 +-#define EP_CONTROL 0 +-#define EP_STATUS 1 +-#define EP_DATA_OUT 2 +-#define EP_DATA_IN 3 +- +-struct ds_device +-{ +- struct usb_device *udev; +- struct usb_interface *intf; +- +- int ep[NUM_EP]; +- +- atomic_t refcnt; +-}; +- +-struct ds_status +-{ +- u8 enable; +- u8 speed; +- u8 pullup_dur; +- u8 ppuls_dur; +- u8 pulldown_slew; +- u8 write1_time; +- u8 write0_time; +- u8 reserved0; +- u8 status; +- u8 command0; +- u8 command1; +- u8 command_buffer_status; +- u8 data_out_buffer_status; +- u8 data_in_buffer_status; +- u8 reserved1; +- u8 reserved2; +- +-}; +- +-int ds_touch_bit(struct ds_device *, u8, u8 *); +-int ds_read_byte(struct ds_device *, u8 *); +-int ds_read_bit(struct ds_device *, u8 *); +-int ds_write_byte(struct ds_device *, u8); +-int ds_write_bit(struct ds_device *, u8); +-int ds_reset(struct ds_device *, struct ds_status *); +-struct ds_device * ds_get_device(void); +-void ds_put_device(struct ds_device *); +-int ds_write_block(struct ds_device *, u8 *, int); +-int ds_read_block(struct ds_device *, u8 *, int); +- +-#endif /* __DSCORE_H */ +- diff --git a/i2c/w1-userspace-communication-protocol-over-connector.patch b/i2c/w1-userspace-communication-protocol-over-connector.patch new file mode 100644 index 0000000000000..08afc9518e743 --- /dev/null +++ b/i2c/w1-userspace-communication-protocol-over-connector.patch @@ -0,0 +1,1045 @@ +From johnpol@2ka.mipt.ru Thu Mar 23 08:00:09 2006 +Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Subject: [PATCH 3/5] w1: Userspace communication protocol over connector. +Date: Thu, 23 Mar 2006 19:11:58 +0300 +Message-Id: <11431303182850@2ka.mipt.ru> +To: GregKH <greg@kroah.com> +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> + + +There are three types of messages between w1 core and userspace: +1. Events. They are generated each time new master or slave device found + either due to automatic or requested search. +2. Userspace commands. Includes read/write and search/alarm search comamnds. +3. Replies to userspace commands. + + +From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + Documentation/w1/w1.netlink | 98 ++++++++++++++++++ + drivers/w1/Makefile | 2 + drivers/w1/slaves/w1_ds2433.c | 1 + drivers/w1/slaves/w1_smem.c | 1 + drivers/w1/slaves/w1_therm.c | 1 + drivers/w1/w1.c | 141 ++++++++++++++++++-------- + drivers/w1/w1.h | 38 +++---- + drivers/w1/w1_family.h | 1 + drivers/w1/w1_int.c | 27 ++--- + drivers/w1/w1_io.c | 18 --- + drivers/w1/w1_netlink.c | 221 +++++++++++++++++++++++++++++++++++------- + drivers/w1/w1_netlink.h | 38 +++++-- + 12 files changed, 450 insertions(+), 137 deletions(-) + +--- /dev/null ++++ gregkh-2.6/Documentation/w1/w1.netlink +@@ -0,0 +1,98 @@ ++Userspace communication protocol over connector [1]. ++ ++ ++Message types. ++============= ++ ++There are three types of messages between w1 core and userspace: ++1. Events. They are generated each time new master or slave device found ++ either due to automatic or requested search. ++2. Userspace commands. Includes read/write and search/alarm search comamnds. ++3. Replies to userspace commands. ++ ++ ++Protocol. ++======== ++ ++[struct cn_msg] - connector header. It's length field is equal to size of the attached data. ++[struct w1_netlink_msg] - w1 netlink header. ++ __u8 type - message type. ++ W1_SLAVE_ADD/W1_SLAVE_REMOVE - slave add/remove events. ++ W1_MASTER_ADD/W1_MASTER_REMOVE - master add/remove events. ++ W1_MASTER_CMD - userspace command for bus master device (search/alarm search). ++ W1_SLAVE_CMD - userspace command for slave device (read/write/ search/alarm search ++ for bus master device where given slave device found). ++ __u8 res - reserved ++ __u16 len - size of attached to this header data. ++ union { ++ __u8 id; - slave unique device id ++ struct w1_mst { ++ __u32 id; - master's id. ++ __u32 res; - reserved ++ } mst; ++ } id; ++ ++[strucrt w1_netlink_cmd] - command for gived master or slave device. ++ __u8 cmd - command opcode. ++ W1_CMD_READ - read command. ++ W1_CMD_WRITE - write command. ++ W1_CMD_SEARCH - search command. ++ W1_CMD_ALARM_SEARCH - alarm search command. ++ __u8 res - reserved ++ __u16 len - length of data for this command. ++ For read command data must be allocated like for write command. ++ __u8 data[0] - data for this command. ++ ++ ++Each connector message can include one or more w1_netlink_msg with zero of more attached w1_netlink_cmd messages. ++ ++For event messages there are no w1_netlink_cmd embedded structures, only connector header ++and w1_netlink_msg strucutre with "len" field being zero and filled type (one of event types) ++and id - either 8 bytes of slave unique id in host order, or master's id, which is assigned ++to bus master device when it is added to w1 core. ++ ++Currently replies to userspace commands are only generated for read command request. ++One reply is generated exactly for one w1_netlink_cmd read request. ++Replies are not combined when sent - i.e. typical reply messages looks like the following: ++[cn_msg][w1_netlink_msg][w1_netlink_cmd] ++cn_msg.len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; ++w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len; ++w1_netlink_cmd.len = cmd->len; ++ ++ ++Operation steps in w1 core when new command is received. ++======================================================= ++ ++When new message (w1_netlink_msg) is received w1 core detects if it is master of slave request, ++according to w1_netlink_msg.type field. ++Then master or slave device is searched for. ++When found, master device (requested or those one on where slave device is found) is locked. ++If slave command is requested, then reset/select procedure is started to select given device. ++ ++Then all requested in w1_netlink_msg operations are performed one by one. ++If command requires reply (like read command) it is sent on command completion. ++ ++When all commands (w1_netlink_cmd) are processed muster device is unlocked ++and next w1_netlink_msg header processing started. ++ ++ ++Connector [1] specific documentation. ++==================================== ++ ++Each connector message includes two u32 fields as "address". ++w1 uses CN_W1_IDX and CN_W1_VAL defined in include/linux/connector.h header. ++Each message also includes sequence and acknowledge numbers. ++Sequence number for event messages is appropriate bus master sequence number increased with ++each event message sent "through" this master. ++Sequence number for userspace requests is set by userspace application. ++Sequence number for reply is the same as was in request, and ++acknowledge number is set to seq+1. ++ ++ ++Additional documantion, source code examples. ++============================================ ++ ++1. Documentation/connector ++2. http://tservice.net.ru/~s0mbre/archive/w1 ++This archive includes userspace application w1d.c which ++uses read/write/search commands for all master/slave devices found on the bus. +--- gregkh-2.6.orig/drivers/w1/Makefile ++++ gregkh-2.6/drivers/w1/Makefile +@@ -2,7 +2,7 @@ + # Makefile for the Dallas's 1-wire bus. + # + +-ifneq ($(CONFIG_NET), y) ++ifeq ($(CONFIG_CONNECTOR), n) + EXTRA_CFLAGS += -DNETLINK_DISABLED + endif + +--- gregkh-2.6.orig/drivers/w1/slaves/w1_ds2433.c ++++ gregkh-2.6/drivers/w1/slaves/w1_ds2433.c +@@ -22,7 +22,6 @@ + #endif + + #include "../w1.h" +-#include "../w1_io.h" + #include "../w1_int.h" + #include "../w1_family.h" + +--- gregkh-2.6.orig/drivers/w1/slaves/w1_smem.c ++++ gregkh-2.6/drivers/w1/slaves/w1_smem.c +@@ -28,7 +28,6 @@ + #include <linux/types.h> + + #include "../w1.h" +-#include "../w1_io.h" + #include "../w1_int.h" + #include "../w1_family.h" + +--- gregkh-2.6.orig/drivers/w1/slaves/w1_therm.c ++++ gregkh-2.6/drivers/w1/slaves/w1_therm.c +@@ -29,7 +29,6 @@ + #include <linux/delay.h> + + #include "../w1.h" +-#include "../w1_io.h" + #include "../w1_int.h" + #include "../w1_family.h" + +--- gregkh-2.6.orig/drivers/w1/w1.c ++++ gregkh-2.6/drivers/w1/w1.c +@@ -35,7 +35,6 @@ + #include <asm/atomic.h> + + #include "w1.h" +-#include "w1_io.h" + #include "w1_log.h" + #include "w1_int.h" + #include "w1_family.h" +@@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_c + module_param_named(max_slave_count, w1_max_slave_count, int, 0); + module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); + +-DEFINE_SPINLOCK(w1_mlock); ++DECLARE_MUTEX(w1_mlock); + LIST_HEAD(w1_masters); + + static struct task_struct *w1_control_thread; +@@ -75,8 +74,6 @@ static void w1_master_release(struct dev + struct w1_master *md = dev_to_w1_master(dev); + + dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); +- +- dev_fini_netlink(md); + memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); + kfree(md); + } +@@ -85,10 +82,10 @@ static void w1_slave_release(struct devi + { + struct w1_slave *sl = dev_to_w1_slave(dev); + +- dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); ++ printk("%s: Releasing %s.\n", __func__, sl->name); + + while (atomic_read(&sl->refcnt)) { +- dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", ++ printk("Waiting for %s to become free: refcnt=%d.\n", + sl->name, atomic_read(&sl->refcnt)); + if (msleep_interruptible(1000)) + flush_signals(current); +@@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct k + { + struct w1_slave *sl = kobj_to_w1_slave(kobj); + +- atomic_inc(&sl->refcnt); + if (off > 8) { + count = 0; + } else { +@@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct k + + memcpy(buf, (u8 *)&sl->reg_num, count); + } +- atomic_dec(&sl->refcnt); + + return count; + } +@@ -230,12 +225,11 @@ struct device w1_master_device = { + .release = &w1_master_release + }; + +-static struct device_driver w1_slave_driver = { ++struct device_driver w1_slave_driver = { + .name = "w1_slave_driver", + .bus = &w1_bus_type, + }; + +-#if 0 + struct device w1_slave_device = { + .parent = NULL, + .bus = &w1_bus_type, +@@ -243,7 +237,6 @@ struct device w1_slave_device = { + .driver = &w1_slave_driver, + .release = &w1_slave_release + }; +-#endif /* 0 */ + + static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) + { +@@ -423,7 +416,7 @@ int w1_create_master_attributes(struct w + return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); + } + +-static void w1_destroy_master_attributes(struct w1_master *master) ++void w1_destroy_master_attributes(struct w1_master *master) + { + sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); + } +@@ -454,14 +447,11 @@ static int w1_uevent(struct device *dev, + if (dev->driver != &w1_slave_driver || !sl) + return 0; + +- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, +- &cur_len, "W1_FID=%02X", sl->reg_num.family); ++ err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family); + if (err) + return err; + +- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, +- &cur_len, "W1_SLAVE_ID=%024LX", +- (unsigned long long)sl->reg_num.id); ++ err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id); + if (err) + return err; + +@@ -563,6 +553,7 @@ static int w1_attach_slave_device(struct + sl->master = dev; + set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + ++ memset(&msg, 0, sizeof(msg)); + memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); + atomic_set(&sl->refcnt, 0); + init_completion(&sl->released); +@@ -593,7 +584,7 @@ static int w1_attach_slave_device(struct + sl->ttl = dev->slave_ttl; + dev->slave_count++; + +- memcpy(&msg.id.id, rn, sizeof(msg.id.id)); ++ memcpy(msg.id.id, rn, sizeof(msg.id)); + msg.type = W1_SLAVE_ADD; + w1_netlink_send(dev, &msg); + +@@ -611,7 +602,8 @@ static void w1_slave_detach(struct w1_sl + if (sl->family->fops && sl->family->fops->remove_slave) + sl->family->fops->remove_slave(sl); + +- memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); ++ memset(&msg, 0, sizeof(msg)); ++ memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); + msg.type = W1_SLAVE_REMOVE; + w1_netlink_send(sl->master, &msg); + +@@ -628,7 +620,7 @@ static struct w1_master *w1_search_maste + struct w1_master *dev; + int found = 0; + +- spin_lock_bh(&w1_mlock); ++ down(&w1_mlock); + list_for_each_entry(dev, &w1_masters, w1_master_entry) { + if (dev->bus_master->data == data) { + found = 1; +@@ -636,22 +628,69 @@ static struct w1_master *w1_search_maste + break; + } + } +- spin_unlock_bh(&w1_mlock); ++ up(&w1_mlock); ++ ++ return (found)?dev:NULL; ++} ++ ++struct w1_master *w1_search_master_id(u32 id) ++{ ++ struct w1_master *dev; ++ int found = 0; ++ ++ down(&w1_mlock); ++ list_for_each_entry(dev, &w1_masters, w1_master_entry) { ++ if (dev->id == id) { ++ found = 1; ++ atomic_inc(&dev->refcnt); ++ break; ++ } ++ } ++ up(&w1_mlock); + + return (found)?dev:NULL; + } + ++struct w1_slave *w1_search_slave(struct w1_reg_num *id) ++{ ++ struct w1_master *dev; ++ struct w1_slave *sl = NULL; ++ int found = 0; ++ ++ down(&w1_mlock); ++ list_for_each_entry(dev, &w1_masters, w1_master_entry) { ++ down(&dev->mutex); ++ list_for_each_entry(sl, &dev->slist, w1_slave_entry) { ++ if (sl->reg_num.family == id->family && ++ sl->reg_num.id == id->id && ++ sl->reg_num.crc == id->crc) { ++ found = 1; ++ atomic_inc(&dev->refcnt); ++ atomic_inc(&sl->refcnt); ++ break; ++ } ++ } ++ up(&dev->mutex); ++ ++ if (found) ++ break; ++ } ++ up(&w1_mlock); ++ ++ return (found)?sl:NULL; ++} ++ + void w1_reconnect_slaves(struct w1_family *f) + { + struct w1_master *dev; + +- spin_lock_bh(&w1_mlock); ++ down(&w1_mlock); + list_for_each_entry(dev, &w1_masters, w1_master_entry) { + dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", + dev->name, f->fid); + set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); + } +- spin_unlock_bh(&w1_mlock); ++ up(&w1_mlock); + } + + static void w1_slave_found(void *data, u64 rn) +@@ -713,7 +752,7 @@ static void w1_slave_found(void *data, u + * @dev The master device to search + * @cb Function to call when a device is found + */ +-void w1_search(struct w1_master *dev, w1_slave_found_callback cb) ++void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) + { + u64 last_rn, rn, tmp64; + int i, slave_count = 0; +@@ -744,7 +783,7 @@ void w1_search(struct w1_master *dev, w1 + } + + /* Start the search */ +- w1_write_8(dev, W1_SEARCH); ++ w1_write_8(dev, search_type); + for (i = 0; i < 64; ++i) { + /* Determine the direction/search bit */ + if (i == desc_bit) +@@ -806,9 +845,9 @@ static int w1_control(void *data) + if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { + set_bit(W1_MASTER_NEED_EXIT, &dev->flags); + +- spin_lock(&w1_mlock); ++ down(&w1_mlock); + list_del(&dev->w1_master_entry); +- spin_unlock(&w1_mlock); ++ up(&w1_mlock); + + down(&dev->mutex); + list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { +@@ -843,10 +882,31 @@ static int w1_control(void *data) + return 0; + } + ++void w1_search_process(struct w1_master *dev, u8 search_type) ++{ ++ struct w1_slave *sl, *sln; ++ ++ list_for_each_entry(sl, &dev->slist, w1_slave_entry) ++ clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); ++ ++ w1_search_devices(dev, search_type, w1_slave_found); ++ ++ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { ++ if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { ++ w1_slave_detach(sl); ++ ++ dev->slave_count--; ++ } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) ++ sl->ttl = dev->slave_ttl; ++ } ++ ++ if (dev->search_count > 0) ++ dev->search_count--; ++} ++ + int w1_process(void *data) + { + struct w1_master *dev = (struct w1_master *) data; +- struct w1_slave *sl, *sln; + + while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { + try_to_freeze(); +@@ -864,28 +924,13 @@ int w1_process(void *data) + if (down_interruptible(&dev->mutex)) + continue; + +- list_for_each_entry(sl, &dev->slist, w1_slave_entry) +- clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); +- +- w1_search_devices(dev, w1_slave_found); +- +- list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { +- if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { +- w1_slave_detach(sl); +- +- dev->slave_count--; +- } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) +- sl->ttl = dev->slave_ttl; +- } +- +- if (dev->search_count > 0) +- dev->search_count--; +- ++ w1_search_process(dev, W1_SEARCH); ++ + up(&dev->mutex); + } + + atomic_dec(&dev->refcnt); +- ++ + return 0; + } + +@@ -895,6 +940,8 @@ static int w1_init(void) + + printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); + ++ w1_init_netlink(); ++ + retval = bus_register(&w1_bus_type); + if (retval) { + printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); +@@ -946,6 +993,8 @@ static void w1_fini(void) + + list_for_each_entry(dev, &w1_masters, w1_master_entry) + __w1_remove_master_device(dev); ++ ++ w1_fini_netlink(); + + kthread_stop(w1_control_thread); + +--- gregkh-2.6.orig/drivers/w1/w1.h ++++ gregkh-2.6/drivers/w1/w1.h +@@ -42,8 +42,6 @@ struct w1_reg_num + #include <linux/completion.h> + #include <linux/device.h> + +-#include <net/sock.h> +- + #include <asm/semaphore.h> + + #include "w1_family.h" +@@ -52,7 +50,7 @@ struct w1_reg_num + #define W1_SLAVE_DATA_SIZE 128 + + #define W1_SEARCH 0xF0 +-#define W1_CONDITIONAL_SEARCH 0xEC ++#define W1_ALARM_SEARCH 0xEC + #define W1_CONVERT_TEMP 0x44 + #define W1_SKIP_ROM 0xCC + #define W1_READ_SCRATCHPAD 0xBE +@@ -145,8 +143,8 @@ struct w1_bus_master + */ + u8 (*reset_bus)(void *); + +- /** Really nice hardware can handles the ROM searches */ +- void (*search)(void *, w1_slave_found_callback); ++ /** Really nice hardware can handles the different types of ROM search */ ++ void (*search)(void *, u8, w1_slave_found_callback); + }; + + #define W1_MASTER_NEED_EXIT 0 +@@ -180,12 +178,26 @@ struct w1_master + + struct w1_bus_master *bus_master; + +- u32 seq, groups; +- struct sock *nls; ++ u32 seq; + }; + + 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, u8 search_type, w1_slave_found_callback cb); ++void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); ++struct w1_slave *w1_search_slave(struct w1_reg_num *id); ++void w1_search_process(struct w1_master *dev, u8 search_type); ++struct w1_master *w1_search_master_id(u32 id); ++ ++void w1_delay(unsigned long); ++u8 w1_touch_bit(struct w1_master *, int); ++u8 w1_triplet(struct w1_master *dev, int bdir); ++void w1_write_8(struct w1_master *, u8); ++u8 w1_read_8(struct w1_master *); ++int w1_reset_bus(struct w1_master *); ++u8 w1_calc_crc8(u8 *, int); ++void w1_write_block(struct w1_master *, const u8 *, int); ++u8 w1_read_block(struct w1_master *, u8 *, int); ++int w1_reset_select_slave(struct w1_slave *sl); + + static inline struct w1_slave* dev_to_w1_slave(struct device *dev) + { +@@ -202,16 +214,6 @@ static inline struct w1_master* dev_to_w + return container_of(dev, struct w1_master, dev); + } + +-extern int w1_max_slave_count; +-extern int w1_max_slave_ttl; +-extern spinlock_t w1_mlock; +-extern struct list_head w1_masters; +-extern struct device_driver w1_master_driver; +-extern struct device w1_master_device; +- +-int w1_process(void *data); +-void w1_reconnect_slaves(struct w1_family *f); +- + #endif /* __KERNEL__ */ + + #endif /* __W1_H */ +--- gregkh-2.6.orig/drivers/w1/w1_family.h ++++ gregkh-2.6/drivers/w1/w1_family.h +@@ -64,5 +64,6 @@ void __w1_family_put(struct w1_family *) + struct w1_family * w1_family_registered(u8); + void w1_unregister_family(struct w1_family *); + int w1_register_family(struct w1_family *); ++void w1_reconnect_slaves(struct w1_family *f); + + #endif /* __W1_FAMILY_H */ +--- gregkh-2.6.orig/drivers/w1/w1_int.c ++++ gregkh-2.6/drivers/w1/w1_int.c +@@ -27,10 +27,19 @@ + #include "w1.h" + #include "w1_log.h" + #include "w1_netlink.h" +-#include "w1_int.h" + + static u32 w1_ids = 1; + ++extern struct device_driver w1_master_driver; ++extern struct bus_type w1_bus_type; ++extern struct device w1_master_device; ++extern int w1_max_slave_count; ++extern int w1_max_slave_ttl; ++extern struct list_head w1_masters; ++extern struct semaphore w1_mlock; ++ ++extern int w1_process(void *); ++ + static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, + struct device_driver *driver, + struct device *device) +@@ -74,16 +83,11 @@ static struct w1_master * w1_alloc_dev(u + + dev->driver = driver; + +- dev->groups = 1; + dev->seq = 1; +- dev_init_netlink(dev); + + err = device_register(&dev->dev); + if (err) { + printk(KERN_ERR "Failed to register master device. err=%d\n", err); +- +- dev_fini_netlink(dev); +- + memset(dev, 0, sizeof(struct w1_master)); + kfree(dev); + dev = NULL; +@@ -92,7 +96,7 @@ static struct w1_master * w1_alloc_dev(u + return dev; + } + +-static void w1_free_dev(struct w1_master *dev) ++void w1_free_dev(struct w1_master *dev) + { + device_unregister(&dev->dev); + } +@@ -131,12 +135,12 @@ int w1_add_master_device(struct w1_bus_m + + dev->initialized = 1; + +- spin_lock(&w1_mlock); ++ down(&w1_mlock); + list_add(&dev->w1_master_entry, &w1_masters); +- spin_unlock(&w1_mlock); ++ up(&w1_mlock); + ++ memset(&msg, 0, sizeof(msg)); + msg.id.mst.id = dev->id; +- msg.id.mst.pid = dev->thread->pid; + msg.type = W1_MASTER_ADD; + w1_netlink_send(dev, &msg); + +@@ -153,7 +157,6 @@ err_out_free_dev: + void __w1_remove_master_device(struct w1_master *dev) + { + struct w1_netlink_msg msg; +- pid_t pid = dev->thread->pid; + + set_bit(W1_MASTER_NEED_EXIT, &dev->flags); + kthread_stop(dev->thread); +@@ -166,8 +169,8 @@ void __w1_remove_master_device(struct w1 + flush_signals(current); + } + ++ memset(&msg, 0, sizeof(msg)); + msg.id.mst.id = dev->id; +- msg.id.mst.pid = pid; + msg.type = W1_MASTER_REMOVE; + w1_netlink_send(dev, &msg); + +--- gregkh-2.6.orig/drivers/w1/w1_io.c ++++ gregkh-2.6/drivers/w1/w1_io.c +@@ -26,7 +26,6 @@ + + #include "w1.h" + #include "w1_log.h" +-#include "w1_io.h" + + static int w1_delay_parm = 1; + module_param_named(delay_coef, w1_delay_parm, int, 0); +@@ -268,13 +267,13 @@ u8 w1_calc_crc8(u8 * data, int len) + return crc; + } + +-void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) ++void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) + { + dev->attempts++; + if (dev->bus_master->search) +- dev->bus_master->search(dev->bus_master->data, cb); ++ dev->bus_master->search(dev->bus_master->data, search_type, cb); + else +- w1_search(dev, cb); ++ w1_search(dev, search_type, cb); + } + + /** +@@ -300,13 +299,4 @@ int w1_reset_select_slave(struct w1_slav + return 0; + } + +-EXPORT_SYMBOL(w1_touch_bit); +-EXPORT_SYMBOL(w1_write_8); +-EXPORT_SYMBOL(w1_read_8); +-EXPORT_SYMBOL(w1_reset_bus); +-EXPORT_SYMBOL(w1_calc_crc8); +-EXPORT_SYMBOL(w1_delay); +-EXPORT_SYMBOL(w1_read_block); +-EXPORT_SYMBOL(w1_write_block); +-EXPORT_SYMBOL(w1_search_devices); +-EXPORT_SYMBOL(w1_reset_select_slave); ++EXPORT_SYMBOL_GPL(w1_calc_crc8); +--- gregkh-2.6.orig/drivers/w1/w1_netlink.c ++++ gregkh-2.6/drivers/w1/w1_netlink.c +@@ -21,6 +21,7 @@ + + #include <linux/skbuff.h> + #include <linux/netlink.h> ++#include <linux/connector.h> + + #include "w1.h" + #include "w1_log.h" +@@ -29,50 +30,204 @@ + #ifndef NETLINK_DISABLED + void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) + { +- unsigned int size; +- struct sk_buff *skb; +- struct w1_netlink_msg *data; +- struct nlmsghdr *nlh; +- +- if (!dev->nls) +- return; +- +- size = NLMSG_SPACE(sizeof(struct w1_netlink_msg)); +- +- skb = alloc_skb(size, GFP_ATOMIC); +- if (!skb) { +- dev_err(&dev->dev, "skb_alloc() failed.\n"); +- return; +- } ++ char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; ++ struct cn_msg *m = (struct cn_msg *)buf; ++ struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); ++ ++ memset(buf, 0, sizeof(buf)); + +- nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh)); ++ m->id.idx = CN_W1_IDX; ++ m->id.val = CN_W1_VAL; + +- data = (struct w1_netlink_msg *)NLMSG_DATA(nlh); ++ m->seq = dev->seq++; ++ m->len = sizeof(struct w1_netlink_msg); + +- memcpy(data, msg, sizeof(struct w1_netlink_msg)); ++ memcpy(w, msg, sizeof(struct w1_netlink_msg)); ++ ++ cn_netlink_send(m, 0, GFP_KERNEL); ++} + +- NETLINK_CB(skb).dst_group = dev->groups; +- netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC); ++static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, ++ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) ++{ ++ dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", ++ __func__, dev->name, cmd->cmd, cmd->len); + +-nlmsg_failure: +- return; ++ if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) ++ return -EINVAL; ++ ++ w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); ++ return 0; + } + +-int dev_init_netlink(struct w1_master *dev) ++static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, ++ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) + { +- 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); ++ void *data; ++ struct w1_netlink_msg *h; ++ struct w1_netlink_cmd *c; ++ struct cn_msg *cm; ++ int err; ++ ++ data = kzalloc(sizeof(struct cn_msg) + ++ sizeof(struct w1_netlink_msg) + ++ sizeof(struct w1_netlink_cmd) + ++ cmd->len, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ cm = (struct cn_msg *)(data); ++ h = (struct w1_netlink_msg *)(cm + 1); ++ c = (struct w1_netlink_cmd *)(h + 1); ++ ++ memcpy(cm, msg, sizeof(struct cn_msg)); ++ memcpy(h, hdr, sizeof(struct w1_netlink_msg)); ++ memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); ++ ++ cm->ack = msg->seq+1; ++ cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; ++ ++ h->len = sizeof(struct w1_netlink_cmd) + cmd->len; ++ ++ memcpy(c->data, cmd->data, c->len); ++ ++ err = cn_netlink_send(cm, 0, GFP_KERNEL); ++ ++ kfree(data); ++ ++ return err; ++} ++ ++static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, ++ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) ++{ ++ int err = 0; ++ ++ dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", ++ __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, ++ cmd->cmd, cmd->len); ++ ++ switch (cmd->cmd) { ++ case W1_CMD_READ: ++ w1_read_block(sl->master, cmd->data, cmd->len); ++ w1_send_read_reply(sl, msg, hdr, cmd); ++ break; ++ case W1_CMD_WRITE: ++ w1_write_block(sl->master, cmd->data, cmd->len); ++ break; ++ case W1_CMD_SEARCH: ++ case W1_CMD_ALARM_SEARCH: ++ w1_search_process(sl->master, ++ (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); ++ break; ++ default: ++ err = -1; ++ break; + } ++ ++ return err; ++} + +- return 0; ++static void w1_cn_callback(void *data) ++{ ++ struct cn_msg *msg = data; ++ struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); ++ struct w1_netlink_cmd *cmd; ++ struct w1_slave *sl; ++ struct w1_master *dev; ++ int err = 0; ++ ++ while (msg->len && !err) { ++ struct w1_reg_num id; ++ u16 mlen = m->len; ++ u8 *cmd_data = m->data; ++ ++ dev = NULL; ++ sl = NULL; ++ ++ memcpy(&id, m->id.id, sizeof(id)); ++#if 0 ++ printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", ++ __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); ++#endif ++ if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { ++ err = -E2BIG; ++ break; ++ } ++ ++ if (!mlen) ++ goto out_cont; ++ ++ if (m->type == W1_MASTER_CMD) { ++ dev = w1_search_master_id(m->id.mst.id); ++ } else if (m->type == W1_SLAVE_CMD) { ++ sl = w1_search_slave(&id); ++ if (sl) ++ dev = sl->master; ++ } ++ ++ if (!dev) { ++ err = -ENODEV; ++ goto out_cont; ++ } ++ ++ down(&dev->mutex); ++ ++ if (sl && w1_reset_select_slave(sl)) { ++ err = -ENODEV; ++ goto out_up; ++ } ++ ++ while (mlen) { ++ cmd = (struct w1_netlink_cmd *)cmd_data; ++ ++ if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { ++ err = -E2BIG; ++ break; ++ } ++ ++ if (sl) ++ w1_process_command_slave(sl, msg, m, cmd); ++ else ++ w1_process_command_master(dev, msg, m, cmd); ++ ++ cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); ++ mlen -= cmd->len + sizeof(struct w1_netlink_cmd); ++ } ++out_up: ++ atomic_dec(&dev->refcnt); ++ if (sl) ++ atomic_dec(&sl->refcnt); ++ up(&dev->mutex); ++out_cont: ++ msg->len -= sizeof(struct w1_netlink_msg) + m->len; ++ m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); ++ ++ /* ++ * Let's allow requests for nonexisting devices. ++ */ ++ if (err == -ENODEV) ++ err = 0; ++ } ++#if 0 ++ if (err) { ++ printk("%s: malformed message. Dropping.\n", __func__); ++ } ++#endif ++} ++ ++int w1_init_netlink(void) ++{ ++ struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; ++ ++ return cn_add_callback(&w1_id, "w1", &w1_cn_callback); + } + +-void dev_fini_netlink(struct w1_master *dev) ++void w1_fini_netlink(void) + { +- if (dev->nls && dev->nls->sk_socket) +- sock_release(dev->nls->sk_socket); ++ struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; ++ ++ cn_del_callback(&w1_id); + } + #else + #warning Netlink support is disabled. Please compile with NET support enabled. +@@ -81,12 +236,12 @@ void w1_netlink_send(struct w1_master *d + { + } + +-int dev_init_netlink(struct w1_master *dev) ++int w1_init_netlink(void) + { + return 0; + } + +-void dev_fini_netlink(struct w1_master *dev) ++void w1_fini_netlink(void) + { + } + #endif +--- gregkh-2.6.orig/drivers/w1/w1_netlink.h ++++ gregkh-2.6/drivers/w1/w1_netlink.h +@@ -23,37 +23,55 @@ + #define __W1_NETLINK_H + + #include <asm/types.h> ++#include <linux/connector.h> + + #include "w1.h" + ++#define CN_W1_IDX 3 ++#define CN_W1_VAL 1 ++ + enum w1_netlink_message_types { + W1_SLAVE_ADD = 0, + W1_SLAVE_REMOVE, + W1_MASTER_ADD, + W1_MASTER_REMOVE, ++ W1_MASTER_CMD, ++ W1_SLAVE_CMD, + }; + + struct w1_netlink_msg + { + __u8 type; +- __u8 reserved[3]; +- union +- { +- struct w1_reg_num id; +- __u64 w1_id; +- struct +- { ++ __u8 reserved; ++ __u16 len; ++ union { ++ __u8 id[8]; ++ struct w1_mst { + __u32 id; +- __u32 pid; ++ __u32 res; + } mst; + } id; ++ __u8 data[0]; ++}; ++ ++#define W1_CMD_READ 0x0 ++#define W1_CMD_WRITE 0x1 ++#define W1_CMD_SEARCH 0x2 ++#define W1_CMD_ALARM_SEARCH 0x3 ++ ++struct w1_netlink_cmd ++{ ++ __u8 cmd; ++ __u8 res; ++ __u16 len; ++ __u8 data[0]; + }; + + #ifdef __KERNEL__ + + 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); ++int w1_init_netlink(void); ++void w1_fini_netlink(void); + + #endif /* __KERNEL__ */ + #endif /* __W1_NETLINK_H */ |