diff options
Diffstat (limited to 'drivers/w1')
| -rw-r--r-- | drivers/w1/masters/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/w1/masters/ds1wm.c | 14 | ||||
| -rw-r--r-- | drivers/w1/masters/ds2490.c | 155 | ||||
| -rw-r--r-- | drivers/w1/masters/mxc_w1.c | 72 | ||||
| -rw-r--r-- | drivers/w1/masters/omap_hdq.c | 3 | ||||
| -rw-r--r-- | drivers/w1/masters/w1-gpio.c | 84 | ||||
| -rw-r--r-- | drivers/w1/slaves/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/w1/slaves/w1_therm.c | 21 | ||||
| -rw-r--r-- | drivers/w1/w1.c | 317 | ||||
| -rw-r--r-- | drivers/w1/w1.h | 182 | ||||
| -rw-r--r-- | drivers/w1/w1_family.c | 12 | ||||
| -rw-r--r-- | drivers/w1/w1_family.h | 13 | ||||
| -rw-r--r-- | drivers/w1/w1_int.c | 41 | ||||
| -rw-r--r-- | drivers/w1/w1_io.c | 102 | ||||
| -rw-r--r-- | drivers/w1/w1_netlink.c | 750 | ||||
| -rw-r--r-- | drivers/w1/w1_netlink.h | 69 | 
16 files changed, 1310 insertions, 533 deletions
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index efc7f075fcb..1708b2300c7 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -36,13 +36,12 @@ config W1_MASTER_DS2482  config W1_MASTER_MXC  	tristate "Freescale MXC 1-wire busmaster" -	depends on W1 && ARCH_MXC +	depends on ARCH_MXC || COMPILE_TEST  	help  	  Say Y here to enable MXC 1-wire host  config W1_MASTER_DS1WM  	tristate "Maxim DS1WM 1-wire busmaster" -	depends on W1  	help  	  Say Y here to enable the DS1WM 1-wire driver, such as that  	  in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 96cab6ac2b4..02df3b1381d 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -255,17 +255,17 @@ static int ds1wm_find_divisor(int gclk)  static void ds1wm_up(struct ds1wm_data *ds1wm_data)  {  	int divisor; -	struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data; +	struct device *dev = &ds1wm_data->pdev->dev; +	struct ds1wm_driver_data *plat = dev_get_platdata(dev);  	if (ds1wm_data->cell->enable)  		ds1wm_data->cell->enable(ds1wm_data->pdev);  	divisor = ds1wm_find_divisor(plat->clock_rate); -	dev_dbg(&ds1wm_data->pdev->dev, -		"found divisor 0x%x for clock %d\n", divisor, plat->clock_rate); +	dev_dbg(dev, "found divisor 0x%x for clock %d\n", +		divisor, plat->clock_rate);  	if (divisor == 0) { -		dev_err(&ds1wm_data->pdev->dev, -			"no suitable divisor for %dHz clock\n", +		dev_err(dev, "no suitable divisor for %dHz clock\n",  			plat->clock_rate);  		return;  	} @@ -481,7 +481,7 @@ static int ds1wm_probe(struct platform_device *pdev)  	ds1wm_data->cell = mfd_get_cell(pdev);  	if (!ds1wm_data->cell)  		return -ENODEV; -	plat = pdev->dev.platform_data; +	plat = dev_get_platdata(&pdev->dev);  	if (!plat)  		return -ENODEV; @@ -498,7 +498,7 @@ static int ds1wm_probe(struct platform_device *pdev)  		irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);  	ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, -			IRQF_DISABLED | IRQF_SHARED, "ds1wm", ds1wm_data); +			IRQF_SHARED, "ds1wm", ds1wm_data);  	if (ret)  		return ret; diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index 4f7e1d770f8..7404ad3062b 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -1,5 +1,5 @@  /* - *	dscore.c + *	ds2490.c  USB to one wire bridge   *   * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>   * @@ -28,6 +28,10 @@  #include "../w1_int.h"  #include "../w1.h" +/* USB Standard */ +/* USB Control request vendor type */ +#define VENDOR				0x40 +  /* COMMAND TYPE CODES */  #define CONTROL_CMD			0x00  #define COMM_CMD			0x01 @@ -107,6 +111,8 @@  #define ST_HALT				0x10  /* DS2490 is currently halted */  #define ST_IDLE				0x20  /* DS2490 is currently idle */  #define ST_EPOF				0x80 +/* Status transfer size, 16 bytes status, 16 byte result flags */ +#define ST_SIZE				0x20  /* Result Register flags */  #define RR_DETECT			0xA5 /* New device detected */ @@ -198,7 +204,7 @@ 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); +			CONTROL_CMD, VENDOR, 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); @@ -213,7 +219,7 @@ 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); +			MODE_CMD, VENDOR, 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); @@ -228,7 +234,7 @@ 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); +			COMM_CMD, VENDOR, value, index, NULL, 0, 1000);  	if (err < 0) {  		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",  				value, index, err); @@ -246,7 +252,8 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,  	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); +	err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(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; @@ -353,7 +360,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)  	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),  				buf, size, &count, 1000);  	if (err < 0) { -		u8 buf[0x20]; +		u8 buf[ST_SIZE];  		int count;  		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]); @@ -398,7 +405,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)  {  	struct ds_status st;  	int count = 0, err = 0; -	u8 buf[0x20]; +	u8 buf[ST_SIZE];  	do {  		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0); @@ -450,10 +457,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)  static int ds_wait_status(struct ds_device *dev, struct ds_status *st)  { -	u8 buf[0x20]; +	u8 buf[ST_SIZE];  	int err, count = 0;  	do { +		st->status = 0;  		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));  #if 0  		if (err >= 0) { @@ -464,7 +472,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)  			printk("\n");  		}  #endif -	} while (!(buf[0x08] & ST_IDLE) && !(err < 0) && ++count < 100); +	} while (!(st->status & ST_IDLE) && !(err < 0) && ++count < 100);  	if (err >= 16 && st->status & ST_EPOF) {  		printk(KERN_INFO "Resetting device after ST_EPOF.\n"); @@ -690,37 +698,106 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)  	return !(err == len);  } -#if 0 - -static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) +static void ds9490r_search(void *data, struct w1_master *master, +	u8 search_type, w1_slave_found_callback callback)  { +	/* When starting with an existing id, the first id returned will +	 * be that device (if it is still on the bus most likely). +	 * +	 * If the number of devices found is less than or equal to the +	 * search_limit, that number of IDs will be returned.  If there are +	 * more, search_limit IDs will be returned followed by a non-zero +	 * discrepency value. +	 */ +	struct ds_device *dev = data;  	int err;  	u16 value, index;  	struct ds_status st; +	u8 st_buf[ST_SIZE]; +	int search_limit; +	int found = 0; +	int i; -	memset(buf, 0, sizeof(buf)); +	/* DS18b20 spec, 13.16 ms per device, 75 per second, sleep for +	 * discovering 8 devices (1 bulk transfer and 1/2 FIFO size) at a time. +	 */ +	const unsigned long jtime = msecs_to_jiffies(1000*8/75); +	/* FIFO 128 bytes, bulk packet size 64, read a multiple of the +	 * packet size. +	 */ +	u64 buf[2*64/8]; -	err = ds_send_data(ds_dev, (unsigned char *)&init, 8); -	if (err) -		return err; +	mutex_lock(&master->bus_mutex); -	ds_wait_status(ds_dev, &st); +	/* address to start searching at */ +	if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0) +		goto search_out; +	master->search_id = 0; -	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; +	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F | +		COMM_RTS; +	search_limit = master->max_slave_count; +	if (search_limit > 255) +		search_limit = 0; +	index = search_type | (search_limit << 8); +	if (ds_send_control(dev, value, index) < 0) +		goto search_out; -	ds_wait_status(ds_dev, &st); +	do { +		schedule_timeout(jtime); -	err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number); -	if (err < 0) -		return err; +		if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) < +			sizeof(st)) { +			break; +		} -	return err/8; +		if (st.data_in_buffer_status) { +			/* Bulk in can receive partial ids, but when it does +			 * they fail crc and will be discarded anyway. +			 * That has only been seen when status in buffer +			 * is 0 and bulk is read anyway, so don't read +			 * bulk without first checking if status says there +			 * is data to read. +			 */ +			err = ds_recv_data(dev, (u8 *)buf, sizeof(buf)); +			if (err < 0) +				break; +			for (i = 0; i < err/8; ++i) { +				++found; +				if (found <= search_limit) +					callback(master, buf[i]); +				/* can't know if there will be a discrepancy +				 * value after until the next id */ +				if (found == search_limit) +					master->search_id = buf[i]; +			} +		} + +		if (test_bit(W1_ABORT_SEARCH, &master->flags)) +			break; +	} while (!(st.status & (ST_IDLE | ST_HALT))); + +	/* only continue the search if some weren't found */ +	if (found <= search_limit) { +		master->search_id = 0; +	} else if (!test_bit(W1_WARN_MAX_COUNT, &master->flags)) { +		/* Only max_slave_count will be scanned in a search, +		 * but it will start where it left off next search +		 * until all ids are identified and then it will start +		 * over.  A continued search will report the previous +		 * last id as the first id (provided it is still on the +		 * bus). +		 */ +		dev_info(&dev->udev->dev, "%s: max_slave_count %d reached, " +			"will continue next search.\n", __func__, +			master->max_slave_count); +		set_bit(W1_WARN_MAX_COUNT, &master->flags); +	} +search_out: +	mutex_unlock(&master->bus_mutex);  } +#if 0  static int ds_match_access(struct ds_device *dev, u64 init)  {  	int err; @@ -894,6 +971,7 @@ static int ds_w1_init(struct ds_device *dev)  	dev->master.write_block	= &ds9490r_write_block;  	dev->master.reset_bus	= &ds9490r_reset;  	dev->master.set_pullup	= &ds9490r_set_pullup; +	dev->master.search	= &ds9490r_search;  	return w1_add_master_device(&dev->master);  } @@ -910,15 +988,13 @@ static int ds_probe(struct usb_interface *intf,  	struct usb_endpoint_descriptor *endpoint;  	struct usb_host_interface *iface_desc;  	struct ds_device *dev; -	int i, err; +	int i, err, alt; -	dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); +	dev = kzalloc(sizeof(struct ds_device), GFP_KERNEL);  	if (!dev) {  		printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");  		return -ENOMEM;  	} -	dev->spu_sleep = 0; -	dev->spu_bit = 0;  	dev->udev = usb_get_dev(udev);  	if (!dev->udev) {  		err = -ENOMEM; @@ -928,20 +1004,25 @@ static int ds_probe(struct usb_interface *intf,  	usb_set_intfdata(intf, dev); -	err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); +	err = usb_reset_configuration(dev->udev);  	if (err) { -		printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", -				intf->altsetting[0].desc.bInterfaceNumber, err); +		dev_err(&dev->udev->dev, +			"Failed to reset configuration: err=%d.\n", err);  		goto err_out_clear;  	} -	err = usb_reset_configuration(dev->udev); +	/* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */ +	alt = 3; +	err = usb_set_interface(dev->udev, +		intf->altsetting[alt].desc.bInterfaceNumber, alt);  	if (err) { -		printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); +		dev_err(&dev->udev->dev, "Failed to set alternative setting %d " +			"for %d interface: err=%d.\n", alt, +			intf->altsetting[alt].desc.bInterfaceNumber, err);  		goto err_out_clear;  	} -	iface_desc = &intf->altsetting[0]; +	iface_desc = &intf->altsetting[alt];  	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; diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 15c7251b055..a5df5e89d45 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -10,24 +10,16 @@   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. - *   */ -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h>  #include <linux/clk.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h>  #include "../w1.h"  #include "../w1_int.h" -#include "../w1_log.h"  /* According to the mx27 Datasheet the reset procedure should take up to about   * 1350us. We set the timeout to 500*100us = 50ms for sure */ @@ -36,17 +28,16 @@  /*   * MXC W1 Register offsets   */ -#define MXC_W1_CONTROL          0x00 -#define MXC_W1_TIME_DIVIDER     0x02 -#define MXC_W1_RESET            0x04 -#define MXC_W1_COMMAND          0x06 -#define MXC_W1_TXRX             0x08 -#define MXC_W1_INTERRUPT        0x0A -#define MXC_W1_INTERRUPT_EN     0x0C +#define MXC_W1_CONTROL		0x00 +# define MXC_W1_CONTROL_RDST	BIT(3) +# define MXC_W1_CONTROL_WR(x)	BIT(5 - (x)) +# define MXC_W1_CONTROL_PST	BIT(6) +# define MXC_W1_CONTROL_RPP	BIT(7) +#define MXC_W1_TIME_DIVIDER	0x02 +#define MXC_W1_RESET		0x04  struct mxc_w1_device {  	void __iomem *regs; -	unsigned int clkdiv;  	struct clk *clk;  	struct w1_bus_master bus_master;  }; @@ -62,12 +53,12 @@ static u8 mxc_w1_ds2_reset_bus(void *data)  	unsigned int timeout_cnt = 0;  	struct mxc_w1_device *dev = data; -	__raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL)); +	writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));  	while (1) { -		reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL); +		reg_val = readb(dev->regs + MXC_W1_CONTROL); -		if (((reg_val >> 7) & 0x1) == 0 || +		if (!(reg_val & MXC_W1_CONTROL_RPP) ||  		    timeout_cnt > MXC_W1_RESET_TIMEOUT)  			break;  		else @@ -75,7 +66,7 @@ static u8 mxc_w1_ds2_reset_bus(void *data)  		udelay(100);  	} -	return (reg_val >> 7) & 0x1; +	return !(reg_val & MXC_W1_CONTROL_PST);  }  /* @@ -91,23 +82,25 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)  					 * datasheet.  					 */ -	__raw_writeb((1 << (5 - bit)), ctrl_addr); +	writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);  	while (timeout_cnt--) { -		if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1)) +		if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))  			break;  		udelay(1);  	} -	return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; +	return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);  }  static int mxc_w1_probe(struct platform_device *pdev)  {  	struct mxc_w1_device *mdev; +	unsigned long clkrate;  	struct resource *res; -	int err = 0; +	unsigned int clkdiv; +	int err;  	mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),  			    GFP_KERNEL); @@ -118,27 +111,39 @@ static int mxc_w1_probe(struct platform_device *pdev)  	if (IS_ERR(mdev->clk))  		return PTR_ERR(mdev->clk); -	mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; +	clkrate = clk_get_rate(mdev->clk); +	if (clkrate < 10000000) +		dev_warn(&pdev->dev, +			 "Low clock frequency causes improper function\n"); + +	clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000); +	clkrate /= clkdiv; +	if ((clkrate < 980000) || (clkrate > 1020000)) +		dev_warn(&pdev->dev, +			 "Incorrect time base frequency %lu Hz\n", clkrate);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	mdev->regs = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(mdev->regs))  		return PTR_ERR(mdev->regs); -	clk_prepare_enable(mdev->clk); -	__raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); +	err = clk_prepare_enable(mdev->clk); +	if (err) +		return err; + +	writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);  	mdev->bus_master.data = mdev;  	mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;  	mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; -	err = w1_add_master_device(&mdev->bus_master); +	platform_set_drvdata(pdev, mdev); +	err = w1_add_master_device(&mdev->bus_master);  	if (err) -		return err; +		clk_disable_unprepare(mdev->clk); -	platform_set_drvdata(pdev, mdev); -	return 0; +	return err;  }  /* @@ -164,6 +169,7 @@ MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);  static struct platform_driver mxc_w1_driver = {  	.driver = {  		.name = "mxc_w1", +		.owner = THIS_MODULE,  		.of_match_table = mxc_w1_dt_ids,  	},  	.probe = mxc_w1_probe, diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 6e94d8dd3d0..9900e8ec739 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -577,8 +577,7 @@ static int omap_hdq_probe(struct platform_device *pdev)  		goto err_irq;  	} -	ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED, -			"omap_hdq", hdq_data); +	ret = devm_request_irq(dev, irq, hdq_isr, 0, "omap_hdq", hdq_data);  	if (ret < 0) {  		dev_dbg(&pdev->dev, "could not request irq\n");  		goto err_irq; diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index f54ece268c9..1d111e56c8c 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -18,10 +18,31 @@  #include <linux/of_gpio.h>  #include <linux/err.h>  #include <linux/of.h> +#include <linux/delay.h>  #include "../w1.h"  #include "../w1_int.h" +static u8 w1_gpio_set_pullup(void *data, int delay) +{ +	struct w1_gpio_platform_data *pdata = data; + +	if (delay) { +		pdata->pullup_duration = delay; +	} else { +		if (pdata->pullup_duration) { +			gpio_direction_output(pdata->pin, 1); + +			msleep(pdata->pullup_duration); + +			gpio_direction_input(pdata->pin); +		} +		pdata->pullup_duration = 0; +	} + +	return 0; +} +  static void w1_gpio_write_bit_dir(void *data, u8 bit)  {  	struct w1_gpio_platform_data *pdata = data; @@ -56,8 +77,9 @@ MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);  static int w1_gpio_probe_dt(struct platform_device *pdev)  { -	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct device_node *np = pdev->dev.of_node; +	int gpio;  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) @@ -66,8 +88,23 @@ static int w1_gpio_probe_dt(struct platform_device *pdev)  	if (of_get_property(np, "linux,open-drain", NULL))  		pdata->is_open_drain = 1; -	pdata->pin = of_get_gpio(np, 0); -	pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); +	gpio = of_get_gpio(np, 0); +	if (gpio < 0) { +		if (gpio != -EPROBE_DEFER) +			dev_err(&pdev->dev, +					"Failed to parse gpio property for data pin (%d)\n", +					gpio); + +		return gpio; +	} +	pdata->pin = gpio; + +	gpio = of_get_gpio(np, 1); +	if (gpio == -EPROBE_DEFER) +		return gpio; +	/* ignore other errors as the pullup gpio is optional */ +	pdata->ext_pullup_enable_pin = gpio; +  	pdev->dev.platform_data = pdata;  	return 0; @@ -81,38 +118,38 @@ static int w1_gpio_probe(struct platform_device *pdev)  	if (of_have_populated_dt()) {  		err = w1_gpio_probe_dt(pdev); -		if (err < 0) { -			dev_err(&pdev->dev, "Failed to parse DT\n"); +		if (err < 0)  			return err; -		}  	} -	pdata = pdev->dev.platform_data; +	pdata = dev_get_platdata(&pdev->dev);  	if (!pdata) {  		dev_err(&pdev->dev, "No configuration data\n");  		return -ENXIO;  	} -	master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); +	master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), +			GFP_KERNEL);  	if (!master) {  		dev_err(&pdev->dev, "Out of memory\n");  		return -ENOMEM;  	} -	err = gpio_request(pdata->pin, "w1"); +	err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");  	if (err) {  		dev_err(&pdev->dev, "gpio_request (pin) failed\n"); -		goto free_master; +		return err;  	}  	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { -		err = gpio_request_one(pdata->ext_pullup_enable_pin, -				       GPIOF_INIT_LOW, "w1 pullup"); +		err = devm_gpio_request_one(&pdev->dev, +				pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, +				"w1 pullup");  		if (err < 0) {  			dev_err(&pdev->dev, "gpio_request_one "  					"(ext_pullup_enable_pin) failed\n"); -			goto free_gpio; +			return err;  		}  	} @@ -125,12 +162,13 @@ static int w1_gpio_probe(struct platform_device *pdev)  	} else {  		gpio_direction_input(pdata->pin);  		master->write_bit = w1_gpio_write_bit_dir; +		master->set_pullup = w1_gpio_set_pullup;  	}  	err = w1_add_master_device(master);  	if (err) {  		dev_err(&pdev->dev, "w1_add_master device failed\n"); -		goto free_gpio_ext_pu; +		return err;  	}  	if (pdata->enable_external_pullup) @@ -142,22 +180,12 @@ static int w1_gpio_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, master);  	return 0; - - free_gpio_ext_pu: -	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) -		gpio_free(pdata->ext_pullup_enable_pin); - free_gpio: -	gpio_free(pdata->pin); - free_master: -	kfree(master); - -	return err;  }  static int w1_gpio_remove(struct platform_device *pdev)  {  	struct w1_bus_master *master = platform_get_drvdata(pdev); -	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);  	if (pdata->enable_external_pullup)  		pdata->enable_external_pullup(0); @@ -166,8 +194,6 @@ static int w1_gpio_remove(struct platform_device *pdev)  		gpio_set_value(pdata->ext_pullup_enable_pin, 0);  	w1_remove_master_device(master); -	gpio_free(pdata->pin); -	kfree(master);  	return 0;  } @@ -176,7 +202,7 @@ static int w1_gpio_remove(struct platform_device *pdev)  static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state)  { -	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);  	if (pdata->enable_external_pullup)  		pdata->enable_external_pullup(0); @@ -186,7 +212,7 @@ static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state)  static int w1_gpio_resume(struct platform_device *pdev)  { -	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);  	if (pdata->enable_external_pullup)  		pdata->enable_external_pullup(1); diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 5e6a3c9e510..1cdce80b6ab 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -72,7 +72,6 @@ config W1_SLAVE_DS2433_CRC  config W1_SLAVE_DS2760  	tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" -	depends on W1  	help  	  If you enable this you will have the DS2760 battery monitor  	  chip support. @@ -85,7 +84,6 @@ config W1_SLAVE_DS2760  config W1_SLAVE_DS2780  	tristate "Dallas 2780 battery monitor chip" -	depends on W1  	help  	  If you enable this you will have the DS2780 battery monitor  	  chip support. @@ -98,7 +96,6 @@ config W1_SLAVE_DS2780  config W1_SLAVE_DS2781  	tristate "Dallas 2781 battery monitor chip" -	depends on W1  	help  	  If you enable this you will have the DS2781 battery monitor  	  chip support. @@ -111,7 +108,6 @@ config W1_SLAVE_DS2781  config W1_SLAVE_DS28E04  	tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)" -	depends on W1  	select CRC16  	help  	  If you enable this you will have the DS28E04-100 @@ -124,7 +120,6 @@ config W1_SLAVE_DS28E04  config W1_SLAVE_BQ27000  	tristate "BQ27000 slave support" -	depends on W1  	help  	  Say Y here if you want to use a hdq  	  bq27000 slave support. diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 8b5ff33f72c..1f11a20a8ab 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -27,6 +27,7 @@  #include <linux/sched.h>  #include <linux/device.h>  #include <linux/types.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include "../w1.h" @@ -58,6 +59,19 @@ MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));  static int w1_strong_pullup = 1;  module_param_named(strong_pullup, w1_strong_pullup, int, 0); +static int w1_therm_add_slave(struct w1_slave *sl) +{ +	sl->family_data = kzalloc(9, GFP_KERNEL); +	if (!sl->family_data) +		return -ENOMEM; +	return 0; +} + +static void w1_therm_remove_slave(struct w1_slave *sl) +{ +	kfree(sl->family_data); +	sl->family_data = NULL; +}  static ssize_t w1_slave_show(struct device *device,  	struct device_attribute *attr, char *buf); @@ -71,6 +85,8 @@ static struct attribute *w1_therm_attrs[] = {  ATTRIBUTE_GROUPS(w1_therm);  static struct w1_family_ops w1_therm_fops = { +	.add_slave	= w1_therm_add_slave, +	.remove_slave	= w1_therm_remove_slave,  	.groups		= w1_therm_groups,  }; @@ -253,12 +269,13 @@ static ssize_t w1_slave_show(struct device *device,  	c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",  			   crc, (verdict) ? "YES" : "NO");  	if (verdict) -		memcpy(sl->rom, rom, sizeof(sl->rom)); +		memcpy(sl->family_data, rom, sizeof(rom));  	else  		dev_warn(device, "Read failed CRC check\n");  	for (i = 0; i < 9; ++i) -		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]); +		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", +			      ((u8 *)sl->family_data)[i]);  	c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",  		w1_convert_temp(rom, sl->family->fid)); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c7c64f18773..5d734152054 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -46,18 +46,29 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");  MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");  static int w1_timeout = 10; -int w1_max_slave_count = 10; +int w1_max_slave_count = 64;  int w1_max_slave_ttl = 10;  module_param_named(timeout, w1_timeout, int, 0); +MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); +/* A search stops when w1_max_slave_count devices have been found in that + * search.  The next search will start over and detect the same set of devices + * on a static 1-wire bus.  Memory is not allocated based on this number, just + * on the number of devices known to the kernel.  Having a high number does not + * consume additional resources.  As a special case, if there is only one + * device on the network and w1_max_slave_count is set to 1, the device id can + * be read directly skipping the normal slower search process. + */  module_param_named(max_slave_count, w1_max_slave_count, int, 0); +MODULE_PARM_DESC(max_slave_count, +	"maximum number of slaves detected in a search");  module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); +MODULE_PARM_DESC(slave_ttl, +	"Number of searches not seeing a slave before it will be removed");  DEFINE_MUTEX(w1_mlock);  LIST_HEAD(w1_masters); -static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn); -  static int w1_master_match(struct device *dev, struct device_driver *drv)  {  	return 1; @@ -81,19 +92,10 @@ static void w1_slave_release(struct device *dev)  {  	struct w1_slave *sl = dev_to_w1_slave(dev); -	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); -	} +	dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);  	w1_family_put(sl->family);  	sl->master->slave_count--; - -	complete(&sl->released);  }  static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -243,7 +245,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,  	mutex_lock(&md->mutex);  	md->search_count = tmp;  	mutex_unlock(&md->mutex); -	wake_up_process(md->thread); +	/* Only wake if it is going to be searching. */ +	if (tmp) +		wake_up_process(md->thread);  	return count;  } @@ -277,7 +281,6 @@ static ssize_t w1_master_attribute_store_pullup(struct device *dev,  	mutex_lock(&md->mutex);  	md->enable_pullup = tmp;  	mutex_unlock(&md->mutex); -	wake_up_process(md->thread);  	return count;  } @@ -314,6 +317,24 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic  	return count;  } +static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	int tmp; +	struct w1_master *md = dev_to_w1_master(dev); + +	if (kstrtoint(buf, 0, &tmp) == -EINVAL || tmp < 1) +		return -EINVAL; + +	mutex_lock(&md->mutex); +	md->max_slave_count = tmp; +	/* allow each time the max_slave_count is updated */ +	clear_bit(W1_WARN_MAX_COUNT, &md->flags); +	mutex_unlock(&md->mutex); + +	return count; +} +  static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct w1_master *md = dev_to_w1_master(dev); @@ -352,23 +373,20 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev,  {  	struct w1_master *md = dev_to_w1_master(dev);  	int c = PAGE_SIZE; +	struct list_head *ent, *n; +	struct w1_slave *sl = NULL; -	mutex_lock(&md->mutex); - -	if (md->slave_count == 0) -		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); -	else { -		struct list_head *ent, *n; -		struct w1_slave *sl; +	mutex_lock(&md->list_mutex); -		list_for_each_safe(ent, n, &md->slist) { -			sl = list_entry(ent, struct w1_slave, w1_slave_entry); +	list_for_each_safe(ent, n, &md->slist) { +		sl = list_entry(ent, struct w1_slave, w1_slave_entry); -			c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name); -		} +		c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);  	} +	if (!sl) +		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); -	mutex_unlock(&md->mutex); +	mutex_unlock(&md->list_mutex);  	return PAGE_SIZE - c;  } @@ -422,19 +440,22 @@ static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,  }  /* Searches the slaves in the w1_master and returns a pointer or NULL. - * Note: must hold the mutex + * Note: must not hold list_mutex   */ -static struct w1_slave *w1_slave_search_device(struct w1_master *dev, +struct w1_slave *w1_slave_search_device(struct w1_master *dev,  	struct w1_reg_num *rn)  {  	struct w1_slave *sl; +	mutex_lock(&dev->list_mutex);  	list_for_each_entry(sl, &dev->slist, w1_slave_entry) {  		if (sl->reg_num.family == rn->family &&  				sl->reg_num.id == rn->id &&  				sl->reg_num.crc == rn->crc) { +			mutex_unlock(&dev->list_mutex);  			return sl;  		}  	} +	mutex_unlock(&dev->list_mutex);  	return NULL;  } @@ -491,7 +512,10 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,  	mutex_lock(&md->mutex);  	sl = w1_slave_search_device(md, &rn);  	if (sl) { -		w1_slave_detach(sl); +		result = w1_slave_detach(sl); +		/* refcnt 0 means it was detached in the call */ +		if (result == 0) +			result = count;  	} else {  		dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,  			(unsigned long long)rn.id); @@ -516,7 +540,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,  static W1_MASTER_ATTR_RO(name, S_IRUGO);  static W1_MASTER_ATTR_RO(slaves, S_IRUGO);  static W1_MASTER_ATTR_RO(slave_count, S_IRUGO); -static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO); +static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);  static W1_MASTER_ATTR_RO(attempts, S_IRUGO);  static W1_MASTER_ATTR_RO(timeout, S_IRUGO);  static W1_MASTER_ATTR_RO(pointer, S_IRUGO); @@ -590,29 +614,16 @@ end:  	return err;  } -/* - * Handle sysfs file creation and removal here, before userspace is told that - * the device is added / removed from the system - */ -static int w1_bus_notify(struct notifier_block *nb, unsigned long action, -			 void *data) +static int w1_family_notify(unsigned long action, struct w1_slave *sl)  { -	struct device *dev = data; -	struct w1_slave *sl;  	struct w1_family_ops *fops;  	int err; -	/* -	 * Only care about slave devices at the moment.  Yes, we should use a -	 * separate "type" for this, but for now, look at the release function -	 * to know which type it is... -	 */ -	if (dev->release != w1_slave_release) -		return 0; - -	sl = dev_to_w1_slave(dev);  	fops = sl->family->fops; +	if (!fops) +		return 0; +  	switch (action) {  	case BUS_NOTIFY_ADD_DEVICE:  		/* if the family driver needs to initialize something... */ @@ -646,10 +657,6 @@ static int w1_bus_notify(struct notifier_block *nb, unsigned long action,  	return 0;  } -static struct notifier_block w1_bus_nb = { -	.notifier_call = w1_bus_notify, -}; -  static int __w1_attach_slave_device(struct w1_slave *sl)  {  	int err; @@ -671,6 +678,9 @@ static int __w1_attach_slave_device(struct w1_slave *sl)  	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,  		dev_name(&sl->dev), sl); +	/* suppress for w1_family_notify before sending KOBJ_ADD */ +	dev_set_uevent_suppress(&sl->dev, true); +  	err = device_register(&sl->dev);  	if (err < 0) {  		dev_err(&sl->dev, @@ -678,17 +688,19 @@ static int __w1_attach_slave_device(struct w1_slave *sl)  			dev_name(&sl->dev), err);  		return err;  	} - +	w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);  	dev_set_uevent_suppress(&sl->dev, false);  	kobject_uevent(&sl->dev.kobj, KOBJ_ADD); +	mutex_lock(&sl->master->list_mutex);  	list_add_tail(&sl->w1_slave_entry, &sl->master->slist); +	mutex_unlock(&sl->master->list_mutex);  	return 0;  } -static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) +int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)  {  	struct w1_slave *sl;  	struct w1_family *f; @@ -706,14 +718,17 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)  	sl->owner = THIS_MODULE;  	sl->master = dev; -	set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); +	set_bit(W1_SLAVE_ACTIVE, &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); +	atomic_set(&sl->refcnt, 1); +	atomic_inc(&sl->master->refcnt); +	/* slave modules need to be loaded in a context with unlocked mutex */ +	mutex_unlock(&dev->mutex);  	request_module("w1-family-0x%0x", rn->family); +	mutex_lock(&dev->mutex);  	spin_lock(&w1_flock);  	f = w1_family_registered(rn->family); @@ -748,23 +763,49 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)  	return 0;  } -void w1_slave_detach(struct w1_slave *sl) +int w1_unref_slave(struct w1_slave *sl)  { -	struct w1_netlink_msg msg; - -	dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl); - -	list_del(&sl->w1_slave_entry); - -	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); - -	device_unregister(&sl->dev); +	struct w1_master *dev = sl->master; +	int refcnt; +	mutex_lock(&dev->list_mutex); +	refcnt = atomic_sub_return(1, &sl->refcnt); +	if (refcnt == 0) { +		struct w1_netlink_msg msg; + +		dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, +			sl->name, sl); + +		list_del(&sl->w1_slave_entry); + +		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); + +		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl); +		device_unregister(&sl->dev); +		#ifdef DEBUG +		memset(sl, 0, sizeof(*sl)); +		#endif +		kfree(sl); +	} +	atomic_dec(&dev->refcnt); +	mutex_unlock(&dev->list_mutex); +	return refcnt; +} -	wait_for_completion(&sl->released); -	kfree(sl); +int w1_slave_detach(struct w1_slave *sl) +{ +	/* Only detach a slave once as it decreases the refcnt each time. */ +	int destroy_now; +	mutex_lock(&sl->master->list_mutex); +	destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags); +	set_bit(W1_SLAVE_DETACH, &sl->flags); +	mutex_unlock(&sl->master->list_mutex); + +	if (destroy_now) +		destroy_now = !w1_unref_slave(sl); +	return destroy_now ? 0 : -EBUSY;  }  struct w1_master *w1_search_master_id(u32 id) @@ -793,7 +834,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)  	mutex_lock(&w1_mlock);  	list_for_each_entry(dev, &w1_masters, w1_master_entry) { -		mutex_lock(&dev->mutex); +		mutex_lock(&dev->list_mutex);  		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {  			if (sl->reg_num.family == id->family &&  					sl->reg_num.id == id->id && @@ -804,7 +845,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)  				break;  			}  		} -		mutex_unlock(&dev->mutex); +		mutex_unlock(&dev->list_mutex);  		if (found)  			break; @@ -824,6 +865,7 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)  		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "  			"for family %02x.\n", dev->name, f->fid);  		mutex_lock(&dev->mutex); +		mutex_lock(&dev->list_mutex);  		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {  			/* If it is a new family, slaves with the default  			 * family driver and are that family will be @@ -835,14 +877,19 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)  				(!attach && sl->family->fid == f->fid)) {  				struct w1_reg_num rn; +				mutex_unlock(&dev->list_mutex);  				memcpy(&rn, &sl->reg_num, sizeof(rn)); -				w1_slave_detach(sl); - -				w1_attach_slave_device(dev, &rn); +				/* If it was already in use let the automatic +				 * scan pick it up again later. +				 */ +				if (!w1_slave_detach(sl)) +					w1_attach_slave_device(dev, &rn); +				mutex_lock(&dev->list_mutex);  			}  		}  		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "  			"has been finished.\n", dev->name); +		mutex_unlock(&dev->list_mutex);  		mutex_unlock(&dev->mutex);  	}  	mutex_unlock(&w1_mlock); @@ -860,7 +907,7 @@ void w1_slave_found(struct w1_master *dev, u64 rn)  	sl = w1_slave_search_device(dev, tmp);  	if (sl) { -		set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); +		set_bit(W1_SLAVE_ACTIVE, &sl->flags);  	} else {  		if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7))  			w1_attach_slave_device(dev, tmp); @@ -870,7 +917,12 @@ void w1_slave_found(struct w1_master *dev, u64 rn)  }  /** - * Performs a ROM Search & registers any devices found. + * w1_search() - Performs a ROM Search & registers any devices found. + * @dev: The master device to search + * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH + * to return only devices in the alarmed state + * @cb: Function to call when a device is found + *   * The 1-wire search is a simple binary tree search.   * For each bit of the address, we read two bits and write one bit.   * The bit written will put to sleep all devies that don't match that bit. @@ -880,8 +932,6 @@ void w1_slave_found(struct w1_master *dev, u64 rn)   *   * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com   * - * @dev        The master device to search - * @cb         Function to call when a device is found   */  void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)  { @@ -892,7 +942,8 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb  	u8  triplet_ret = 0;  	search_bit = 0; -	rn = last_rn = 0; +	rn = dev->search_id; +	last_rn = 0;  	last_device = 0;  	last_zero = -1; @@ -939,7 +990,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb  			else  				search_bit = ((last_rn >> i) & 0x1); -			/** Read two bits and write one bit */ +			/* Read two bits and write one bit */  			triplet_ret = w1_triplet(dev, search_bit);  			/* quit if no device responded */ @@ -954,8 +1005,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb  			tmp64 = (triplet_ret >> 2);  			rn |= (tmp64 << i); -			/* ensure we're called from kthread and not by netlink callback */ -			if (!dev->priv && kthread_should_stop()) { +			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {  				mutex_unlock(&dev->bus_mutex);  				dev_dbg(&dev->dev, "Abort w1_search\n");  				return; @@ -964,11 +1014,30 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb  		mutex_unlock(&dev->bus_mutex);  		if ( (triplet_ret & 0x03) != 0x03 ) { -			if ( (desc_bit == last_zero) || (last_zero < 0)) +			if ((desc_bit == last_zero) || (last_zero < 0)) {  				last_device = 1; +				dev->search_id = 0; +			} else { +				dev->search_id = rn; +			}  			desc_bit = last_zero;  			cb(dev, rn);  		} + +		if (!last_device && slave_count == dev->max_slave_count && +			!test_bit(W1_WARN_MAX_COUNT, &dev->flags)) { +			/* Only max_slave_count will be scanned in a search, +			 * but it will start where it left off next search +			 * until all ids are identified and then it will start +			 * over.  A continued search will report the previous +			 * last id as the first id (provided it is still on the +			 * bus). +			 */ +			dev_info(&dev->dev, "%s: max_slave_count %d reached, " +				"will continue next search.\n", __func__, +				dev->max_slave_count); +			set_bit(W1_WARN_MAX_COUNT, &dev->flags); +		}  	}  } @@ -977,17 +1046,24 @@ void w1_search_process_cb(struct w1_master *dev, u8 search_type,  {  	struct w1_slave *sl, *sln; +	mutex_lock(&dev->list_mutex);  	list_for_each_entry(sl, &dev->slist, w1_slave_entry) -		clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); +		clear_bit(W1_SLAVE_ACTIVE, &sl->flags); +	mutex_unlock(&dev->list_mutex);  	w1_search_devices(dev, search_type, cb); +	mutex_lock(&dev->list_mutex);  	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, &sl->flags) && !--sl->ttl) { +			mutex_unlock(&dev->list_mutex);  			w1_slave_detach(sl); -		else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) +			mutex_lock(&dev->list_mutex); +		} +		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))  			sl->ttl = dev->slave_ttl;  	} +	mutex_unlock(&dev->list_mutex);  	if (dev->search_count > 0)  		dev->search_count--; @@ -998,6 +1074,34 @@ static void w1_search_process(struct w1_master *dev, u8 search_type)  	w1_search_process_cb(dev, search_type, w1_slave_found);  } +/** + * w1_process_callbacks() - execute each dev->async_list callback entry + * @dev: w1_master device + * + * The w1 master list_mutex must be held. + * + * Return: 1 if there were commands to executed 0 otherwise + */ +int w1_process_callbacks(struct w1_master *dev) +{ +	int ret = 0; +	struct w1_async_cmd *async_cmd, *async_n; + +	/* The list can be added to in another thread, loop until it is empty */ +	while (!list_empty(&dev->async_list)) { +		list_for_each_entry_safe(async_cmd, async_n, &dev->async_list, +			async_entry) { +			/* drop the lock, if it is a search it can take a long +			 * time */ +			mutex_unlock(&dev->list_mutex); +			async_cmd->cb(dev, async_cmd); +			ret = 1; +			mutex_lock(&dev->list_mutex); +		} +	} +	return ret; +} +  int w1_process(void *data)  {  	struct w1_master *dev = (struct w1_master *) data; @@ -1005,23 +1109,46 @@ int w1_process(void *data)  	 * time can be calculated in jiffies once.  	 */  	const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000); +	/* remainder if it woke up early */ +	unsigned long jremain = 0; -	while (!kthread_should_stop()) { -		if (dev->search_count) { +	for (;;) { + +		if (!jremain && dev->search_count) {  			mutex_lock(&dev->mutex);  			w1_search_process(dev, W1_SEARCH);  			mutex_unlock(&dev->mutex);  		} +		mutex_lock(&dev->list_mutex); +		/* Note, w1_process_callback drops the lock while processing, +		 * but locks it again before returning. +		 */ +		if (!w1_process_callbacks(dev) && jremain) { +			/* a wake up is either to stop the thread, process +			 * callbacks, or search, it isn't process callbacks, so +			 * schedule a search. +			 */ +			jremain = 1; +		} +  		try_to_freeze();  		__set_current_state(TASK_INTERRUPTIBLE); +		/* hold list_mutex until after interruptible to prevent loosing +		 * the wakeup signal when async_cmd is added. +		 */ +		mutex_unlock(&dev->list_mutex); +  		if (kthread_should_stop())  			break;  		/* Only sleep when the search is active. */ -		if (dev->search_count) -			schedule_timeout(jtime); +		if (dev->search_count) { +			if (!jremain) +				jremain = jtime; +			jremain = schedule_timeout(jremain); +		}  		else  			schedule();  	} @@ -1045,10 +1172,6 @@ static int __init w1_init(void)  		goto err_out_exit_init;  	} -	retval = bus_register_notifier(&w1_bus_type, &w1_bus_nb); -	if (retval) -		goto err_out_bus_unregister; -  	retval = driver_register(&w1_master_driver);  	if (retval) {  		printk(KERN_ERR diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 45908e56c2f..56a49ba41d8 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -22,6 +22,13 @@  #ifndef __W1_H  #define __W1_H +/** + * struct w1_reg_num - broken out slave device id + * + * @family: identifies the type of device + * @id: along with family is the unique device id + * @crc: checksum of the other bytes + */  struct w1_reg_num  {  #if defined(__LITTLE_ENDIAN_BITFIELD) @@ -58,7 +65,24 @@ struct w1_reg_num  #define W1_RESUME_CMD		0xA5  #define W1_SLAVE_ACTIVE		0 +#define W1_SLAVE_DETACH		1 +/** + * struct w1_slave - holds a single slave device on the bus + * + * @owner: Points to the one wire "wire" kernel module. + * @name: Device id is ascii. + * @w1_slave_entry: data for the linked list + * @reg_num: the slave id in binary + * @refcnt: reference count, delete when 0 + * @flags: bit flags for W1_SLAVE_ACTIVE W1_SLAVE_DETACH + * @ttl: decrement per search this slave isn't found, deatch at 0 + * @master: bus which this slave is on + * @family: module for device family type + * @family_data: pointer for use by the family module + * @dev: kernel device identifier + * + */  struct w1_slave  {  	struct module		*owner; @@ -66,118 +90,163 @@ struct w1_slave  	struct list_head	w1_slave_entry;  	struct w1_reg_num	reg_num;  	atomic_t		refcnt; -	u8			rom[9]; -	u32			flags;  	int			ttl; +	unsigned long		flags;  	struct w1_master	*master;  	struct w1_family	*family;  	void			*family_data;  	struct device		dev; -	struct completion	released;  };  typedef void (*w1_slave_found_callback)(struct w1_master *, u64);  /** + * struct w1_bus_master - operations available on a bus master + * + * @data: the first parameter in all the functions below + * + * @read_bit: Sample the line level @return the level read (0 or 1) + * + * @write_bit: Sets the line level + * + * @touch_bit: the lowest-level function for devices that really support the + * 1-wire protocol. + * touch_bit(0) = write-0 cycle + * touch_bit(1) = write-1 / read cycle + * @return the bit read (0 or 1) + * + * @read_byte: Reads a bytes. Same as 8 touch_bit(1) calls. + * @return the byte read + * + * @write_byte: Writes a byte. Same as 8 touch_bit(x) calls. + * + * @read_block: Same as a series of read_byte() calls + * @return the number of bytes read + * + * @write_block: Same as a series of write_byte() calls + * + * @triplet: Combines two reads and a smart write for ROM searches + * @return bit0=Id bit1=comp_id bit2=dir_taken + * + * @reset_bus: long write-0 with a read for the presence pulse detection + * @return -1=Error, 0=Device present, 1=No device present + * + * @set_pullup: Put out a strong pull-up pulse of the specified duration. + * @return -1=Error, 0=completed + * + * @search: Really nice hardware can handles the different types of ROM search + * w1_master* is passed to the slave found callback. + * u8 is search_type, W1_SEARCH or W1_ALARM_SEARCH + *   * Note: read_bit and write_bit are very low level functions and should only   * be used with hardware that doesn't really support 1-wire operations,   * like a parallel/serial port.   * Either define read_bit and write_bit OR define, at minimum, touch_bit and   * reset_bus. + *   */  struct w1_bus_master  { -	/** the first parameter in all the functions below */  	void		*data; -	/** -	 * Sample the line level -	 * @return the level read (0 or 1) -	 */  	u8		(*read_bit)(void *); -	/** Sets the line level */  	void		(*write_bit)(void *, u8); -	/** -	 * touch_bit is the lowest-level function for devices that really -	 * support the 1-wire protocol. -	 * touch_bit(0) = write-0 cycle -	 * touch_bit(1) = write-1 / read cycle -	 * @return the bit read (0 or 1) -	 */  	u8		(*touch_bit)(void *, u8); -	/** -	 * Reads a bytes. Same as 8 touch_bit(1) calls. -	 * @return the byte read -	 */  	u8		(*read_byte)(void *); -	/** -	 * Writes a byte. Same as 8 touch_bit(x) calls. -	 */  	void		(*write_byte)(void *, u8); -	/** -	 * Same as a series of read_byte() calls -	 * @return the number of bytes read -	 */  	u8		(*read_block)(void *, u8 *, int); -	/** Same as a series of write_byte() calls */  	void		(*write_block)(void *, const u8 *, int); -	/** -	 * Combines two reads and a smart write for ROM searches -	 * @return bit0=Id bit1=comp_id bit2=dir_taken -	 */  	u8		(*triplet)(void *, u8); -	/** -	 * long write-0 with a read for the presence pulse detection -	 * @return -1=Error, 0=Device present, 1=No device present -	 */  	u8		(*reset_bus)(void *); -	/** -	 * Put out a strong pull-up pulse of the specified duration. -	 * @return -1=Error, 0=completed -	 */  	u8		(*set_pullup)(void *, int); -	/** Really nice hardware can handles the different types of ROM search -	 *  w1_master* is passed to the slave found callback. -	 */  	void		(*search)(void *, struct w1_master *,  		u8, w1_slave_found_callback);  }; +/** + * enum w1_master_flags - bitfields used in w1_master.flags + * @W1_ABORT_SEARCH: abort searching early on shutdown + * @W1_WARN_MAX_COUNT: limit warning when the maximum count is reached + */ +enum w1_master_flags { +	W1_ABORT_SEARCH = 0, +	W1_WARN_MAX_COUNT = 1, +}; + +/** + * struct w1_master - one per bus master + * @w1_master_entry:	master linked list + * @owner:		module owner + * @name:		dynamically allocate bus name + * @list_mutex:		protect slist and async_list + * @slist:		linked list of slaves + * @async_list:		linked list of netlink commands to execute + * @max_slave_count:	maximum number of slaves to search for at a time + * @slave_count:	current number of slaves known + * @attempts:		number of searches ran + * @slave_ttl:		number of searches before a slave is timed out + * @initialized:	prevent init/removal race conditions + * @id:			w1 bus number + * @search_count:	number of automatic searches to run, -1 unlimited + * @search_id:		allows continuing a search + * @refcnt:		reference count + * @priv:		private data storage + * @enable_pullup:	allows a strong pullup + * @pullup_duration:	time for the next strong pullup + * @flags:		one of w1_master_flags + * @thread:		thread for bus search and netlink commands + * @mutex:		protect most of w1_master + * @bus_mutex:		pretect concurrent bus access + * @driver:		sysfs driver + * @dev:		sysfs device + * @bus_master:		io operations available + * @seq:		sequence number used for netlink broadcasts + */  struct w1_master  {  	struct list_head	w1_master_entry;  	struct module		*owner;  	unsigned char		name[W1_MAXNAMELEN]; +	/* list_mutex protects just slist and async_list so slaves can be +	 * searched for and async commands added while the master has +	 * w1_master.mutex locked and is operating on the bus. +	 * lock order w1_mlock, w1_master.mutex, w1_master.list_mutex +	 */ +	struct mutex		list_mutex;  	struct list_head	slist; +	struct list_head	async_list;  	int			max_slave_count, slave_count;  	unsigned long		attempts;  	int			slave_ttl;  	int			initialized;  	u32			id;  	int			search_count; +	/* id to start searching on, to continue a search or 0 to restart */ +	u64			search_id;  	atomic_t		refcnt;  	void			*priv; -	int			priv_size;  	/** 5V strong pullup enabled flag, 1 enabled, zero disabled. */  	int			enable_pullup;  	/** 5V strong pullup duration in milliseconds, zero disabled. */  	int			pullup_duration; +	long			flags; +  	struct task_struct	*thread;  	struct mutex		mutex;  	struct mutex		bus_mutex; @@ -190,14 +259,34 @@ struct w1_master  	u32			seq;  }; +/** + * struct w1_async_cmd - execute callback from the w1_process kthread + * @async_entry: link entry + * @cb: callback function, must list_del and destroy this list before + * returning + * + * When inserted into the w1_master async_list, w1_process will execute + * the callback.  Embed this into the structure with the command details. + */ +struct w1_async_cmd { +	struct list_head	async_entry; +	void (*cb)(struct w1_master *dev, struct w1_async_cmd *async_cmd); +}; +  int w1_create_master_attributes(struct w1_master *);  void w1_destroy_master_attributes(struct w1_master *master);  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); +/* call w1_unref_slave to release the reference counts w1_search_slave added */  struct w1_slave *w1_search_slave(struct w1_reg_num *id); +/* decrements the reference on sl->master and sl, and cleans up if zero + * returns the reference count after it has been decremented */ +int w1_unref_slave(struct w1_slave *sl);  void w1_slave_found(struct w1_master *dev, u64 rn);  void w1_search_process_cb(struct w1_master *dev, u8 search_type,  	w1_slave_found_callback cb); +struct w1_slave *w1_slave_search_device(struct w1_master *dev, +	struct w1_reg_num *rn);  struct w1_master *w1_search_master_id(u32 id);  /* Disconnect and reconnect devices in the given family.  Used for finding @@ -206,7 +295,9 @@ struct w1_master *w1_search_master_id(u32 id);   * has just been registered, to 0 when it has been unregistered.   */  void w1_reconnect_slaves(struct w1_family *f, int attach); -void w1_slave_detach(struct w1_slave *sl); +int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn); +/* 0 success, otherwise EBUSY */ +int w1_slave_detach(struct w1_slave *sl);  u8 w1_triplet(struct w1_master *dev, int bdir);  void w1_write_8(struct w1_master *, u8); @@ -242,6 +333,7 @@ extern int w1_max_slave_ttl;  extern struct list_head w1_masters;  extern struct mutex w1_mlock; +extern int w1_process_callbacks(struct w1_master *dev);  extern int w1_process(void *);  #endif /* __KERNEL__ */ diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index e9309778ee7..3651ec801f4 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -31,6 +31,10 @@  DEFINE_SPINLOCK(w1_flock);  static LIST_HEAD(w1_families); +/** + * w1_register_family() - register a device family driver + * @newf:	family to register + */  int w1_register_family(struct w1_family *newf)  {  	struct list_head *ent, *n; @@ -59,6 +63,10 @@ int w1_register_family(struct w1_family *newf)  	return ret;  } +/** + * w1_unregister_family() - unregister a device family driver + * @fent:	family to unregister + */  void w1_unregister_family(struct w1_family *fent)  {  	struct list_head *ent, *n; @@ -131,9 +139,9 @@ void w1_family_get(struct w1_family *f)  void __w1_family_get(struct w1_family *f)  { -	smp_mb__before_atomic_inc(); +	smp_mb__before_atomic();  	atomic_inc(&f->refcnt); -	smp_mb__after_atomic_inc(); +	smp_mb__after_atomic();  }  EXPORT_SYMBOL(w1_unregister_family); diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 4ad0e81b640..26ca1343055 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -48,6 +48,12 @@  struct w1_slave; +/** + * struct w1_family_ops - operations for a family type + * @add_slave: add_slave + * @remove_slave: remove_slave + * @groups: sysfs group + */  struct w1_family_ops  {  	int  (* add_slave)(struct w1_slave *); @@ -55,6 +61,13 @@ struct w1_family_ops  	const struct attribute_group **groups;  }; +/** + * struct w1_family - reference counted family structure. + * @family_entry:	family linked list + * @fid:		8 bit family identifier + * @fops:		operations for this family + * @refcnt:		reference counter + */  struct w1_family  {  	struct list_head	family_entry; diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 5a98649f6ab..728039d2efe 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -75,8 +75,10 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,  	atomic_set(&dev->refcnt, 2);  	INIT_LIST_HEAD(&dev->slist); +	INIT_LIST_HEAD(&dev->async_list);  	mutex_init(&dev->mutex);  	mutex_init(&dev->bus_mutex); +	mutex_init(&dev->list_mutex);  	memcpy(&dev->dev, device, sizeof(struct device));  	dev_set_name(&dev->dev, "w1_bus_master%u", dev->id); @@ -103,6 +105,10 @@ static void w1_free_dev(struct w1_master *dev)  	device_unregister(&dev->dev);  } +/** + * w1_add_master_device() - registers a new master device + * @master:	master bus device to register + */  int w1_add_master_device(struct w1_bus_master *master)  {  	struct w1_master *dev, *entry; @@ -117,18 +123,6 @@ int w1_add_master_device(struct w1_bus_master *master)  		printk(KERN_ERR "w1_add_master_device: invalid function set\n");  		return(-EINVAL);          } -	/* While it would be electrically possible to make a device that -	 * generated a strong pullup in bit bang mode, only hardware that -	 * controls 1-wire time frames are even expected to support a strong -	 * pullup.  w1_io.c would need to support calling set_pullup before -	 * the last write_bit operation of a w1_write_8 which it currently -	 * doesn't. -	 */ -	if (!master->write_byte && !master->touch_bit && master->set_pullup) { -		printk(KERN_ERR "w1_add_master_device: set_pullup requires " -			"write_byte or touch_bit, disabling\n"); -		master->set_pullup = NULL; -	}  	/* Lock until the device is added (or not) to w1_masters. */  	mutex_lock(&w1_mlock); @@ -184,6 +178,7 @@ int w1_add_master_device(struct w1_bus_master *master)  #if 0 /* Thread cleanup code, not required currently. */  err_out_kill_thread: +	set_bit(W1_ABORT_SEARCH, &dev->flags);  	kthread_stop(dev->thread);  #endif  err_out_rm_attr: @@ -199,16 +194,22 @@ void __w1_remove_master_device(struct w1_master *dev)  	struct w1_netlink_msg msg;  	struct w1_slave *sl, *sln; -	kthread_stop(dev->thread); -  	mutex_lock(&w1_mlock);  	list_del(&dev->w1_master_entry);  	mutex_unlock(&w1_mlock); +	set_bit(W1_ABORT_SEARCH, &dev->flags); +	kthread_stop(dev->thread); +  	mutex_lock(&dev->mutex); -	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) +	mutex_lock(&dev->list_mutex); +	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { +		mutex_unlock(&dev->list_mutex);  		w1_slave_detach(sl); +		mutex_lock(&dev->list_mutex); +	}  	w1_destroy_master_attributes(dev); +	mutex_unlock(&dev->list_mutex);  	mutex_unlock(&dev->mutex);  	atomic_dec(&dev->refcnt); @@ -218,7 +219,13 @@ void __w1_remove_master_device(struct w1_master *dev)  		if (msleep_interruptible(1000))  			flush_signals(current); +		mutex_lock(&dev->list_mutex); +		w1_process_callbacks(dev); +		mutex_unlock(&dev->list_mutex);  	} +	mutex_lock(&dev->list_mutex); +	w1_process_callbacks(dev); +	mutex_unlock(&dev->list_mutex);  	memset(&msg, 0, sizeof(msg));  	msg.id.mst.id = dev->id; @@ -228,6 +235,10 @@ void __w1_remove_master_device(struct w1_master *dev)  	w1_free_dev(dev);  } +/** + * w1_remove_master_device() - unregister a master device + * @bm:	master bus device to remove + */  void w1_remove_master_device(struct w1_bus_master *bm)  {  	struct w1_master *dev, *found = NULL; diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index e10acc23773..282092421cc 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -62,7 +62,9 @@ static void w1_write_bit(struct w1_master *dev, int bit);  static u8 w1_read_bit(struct w1_master *dev);  /** - * Generates a write-0 or write-1 cycle and samples the level. + * w1_touch_bit() - Generates a write-0 or write-1 cycle and samples the level. + * @dev:	the master device + * @bit:	0 - write a 0, 1 - write a 0 read the level   */  static u8 w1_touch_bit(struct w1_master *dev, int bit)  { @@ -77,7 +79,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)  }  /** - * Generates a write-0 or write-1 cycle. + * w1_write_bit() - Generates a write-0 or write-1 cycle. + * @dev:	the master device + * @bit:	bit to write + *   * Only call if dev->bus_master->touch_bit is NULL   */  static void w1_write_bit(struct w1_master *dev, int bit) @@ -102,11 +107,12 @@ static void w1_write_bit(struct w1_master *dev, int bit)  }  /** + * w1_pre_write() - pre-write operations + * @dev:	the master device + *   * Pre-write operation, currently only supporting strong pullups.   * Program the hardware for a strong pullup, if one has been requested and   * the hardware supports it. - * - * @param dev     the master device   */  static void w1_pre_write(struct w1_master *dev)  { @@ -118,11 +124,12 @@ static void w1_pre_write(struct w1_master *dev)  }  /** + * w1_post_write() - post-write options + * @dev:	the master device + *   * Post-write operation, currently only supporting strong pullups.   * If a strong pullup was requested, clear it if the hardware supports   * them, or execute the delay otherwise, in either case clear the request. - * - * @param dev     the master device   */  static void w1_post_write(struct w1_master *dev)  { @@ -136,10 +143,9 @@ static void w1_post_write(struct w1_master *dev)  }  /** - * Writes 8 bits. - * - * @param dev     the master device - * @param byte    the byte to write + * w1_write_8() - Writes 8 bits. + * @dev:	the master device + * @byte:	the byte to write   */  void w1_write_8(struct w1_master *dev, u8 byte)  { @@ -161,7 +167,9 @@ EXPORT_SYMBOL_GPL(w1_write_8);  /** - * Generates a write-1 cycle and samples the level. + * w1_read_bit() - Generates a write-1 cycle and samples the level. + * @dev:	the master device + *   * Only call if dev->bus_master->touch_bit is NULL   */  static u8 w1_read_bit(struct w1_master *dev) @@ -185,16 +193,17 @@ static u8 w1_read_bit(struct w1_master *dev)  }  /** - * Does a triplet - used for searching ROM addresses. + * w1_triplet() - * Does a triplet - used for searching ROM addresses. + * @dev:	the master device + * @bdir:	the bit to write if both id_bit and comp_bit are 0 + *   * Return bits:   *  bit 0 = id_bit   *  bit 1 = comp_bit   *  bit 2 = dir_taken   * If both bits 0 & 1 are set, the search should be restarted.   * - * @param dev     the master device - * @param bdir    the bit to write if both id_bit and comp_bit are 0 - * @return        bit fields - see above + * Return:        bit fields - see above   */  u8 w1_triplet(struct w1_master *dev, int bdir)  { @@ -226,10 +235,10 @@ u8 w1_triplet(struct w1_master *dev, int bdir)  }  /** - * Reads 8 bits. + * w1_read_8() - Reads 8 bits. + * @dev:	the master device   * - * @param dev     the master device - * @return        the byte read + * Return:        the byte read   */  u8 w1_read_8(struct w1_master *dev)  { @@ -247,11 +256,10 @@ u8 w1_read_8(struct w1_master *dev)  EXPORT_SYMBOL_GPL(w1_read_8);  /** - * Writes a series of bytes. - * - * @param dev     the master device - * @param buf     pointer to the data to write - * @param len     the number of bytes to write + * w1_write_block() - Writes a series of bytes. + * @dev:	the master device + * @buf:	pointer to the data to write + * @len:	the number of bytes to write   */  void w1_write_block(struct w1_master *dev, const u8 *buf, int len)  { @@ -269,11 +277,10 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)  EXPORT_SYMBOL_GPL(w1_write_block);  /** - * Touches a series of bytes. - * - * @param dev     the master device - * @param buf     pointer to the data to write - * @param len     the number of bytes to write + * w1_touch_block() - Touches a series of bytes. + * @dev:	the master device + * @buf:	pointer to the data to write + * @len:	the number of bytes to write   */  void w1_touch_block(struct w1_master *dev, u8 *buf, int len)  { @@ -294,12 +301,11 @@ void w1_touch_block(struct w1_master *dev, u8 *buf, int len)  EXPORT_SYMBOL_GPL(w1_touch_block);  /** - * Reads a series of bytes. - * - * @param dev     the master device - * @param buf     pointer to the buffer to fill - * @param len     the number of bytes to read - * @return        the number of bytes read + * w1_read_block() - Reads a series of bytes. + * @dev:	the master device + * @buf:	pointer to the buffer to fill + * @len:	the number of bytes to read + * Return:	the number of bytes read   */  u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)  { @@ -319,10 +325,9 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)  EXPORT_SYMBOL_GPL(w1_read_block);  /** - * Issues a reset bus sequence. - * - * @param  dev The bus master pointer - * @return     0=Device present, 1=No device present or error + * w1_reset_bus() - Issues a reset bus sequence. + * @dev:	the master device + * Return:	0=Device present, 1=No device present or error   */  int w1_reset_bus(struct w1_master *dev)  { @@ -383,12 +388,15 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal  }  /** + * w1_reset_select_slave() - reset and select a slave + * @sl:		the slave to select + *   * Resets the bus and then selects the slave by sending either a skip rom - * or a rom match. + * or a rom match.  A skip rom is issued if there is only one device + * registered on the bus.   * The w1 master lock must be held.   * - * @param sl	the slave to select - * @return 	0=success, anything else=error + * Return:	0=success, anything else=error   */  int w1_reset_select_slave(struct w1_slave *sl)  { @@ -409,6 +417,9 @@ int w1_reset_select_slave(struct w1_slave *sl)  EXPORT_SYMBOL_GPL(w1_reset_select_slave);  /** + * w1_reset_resume_command() - resume instead of another match ROM + * @dev:	the master device + *   * When the workflow with a slave amongst many requires several   * successive commands a reset between each, this function is similar   * to doing a reset then a match ROM for the last matched ROM. The @@ -420,8 +431,6 @@ EXPORT_SYMBOL_GPL(w1_reset_select_slave);   * doesn't work of course, but the resume command is the next best thing.   *   * The w1 master lock must be held. - * - * @param dev     the master device   */  int w1_reset_resume_command(struct w1_master *dev)  { @@ -435,6 +444,10 @@ int w1_reset_resume_command(struct w1_master *dev)  EXPORT_SYMBOL_GPL(w1_reset_resume_command);  /** + * w1_next_pullup() - register for a strong pullup + * @dev:	the master device + * @delay:	time in milliseconds + *   * Put out a strong pull-up of the specified duration after the next write   * operation.  Not all hardware supports strong pullups.  Hardware that   * doesn't support strong pullups will sleep for the given time after the @@ -442,8 +455,7 @@ EXPORT_SYMBOL_GPL(w1_reset_resume_command);   * the next write, specifying zero will clear a previous request.   * The w1 master lock must be held.   * - * @param delay	time in milliseconds - * @return	0=success, anything else=error + * Return:	0=success, anything else=error   */  void w1_next_pullup(struct w1_master *dev, int delay)  { diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 40788c925d1..351a2978ba7 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -29,128 +29,294 @@  #include "w1_netlink.h"  #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) -void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) -{ -	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)); -	m->id.idx = CN_W1_IDX; -	m->id.val = CN_W1_VAL; +#define MIN(a, b)                   (((a) < (b)) ? (a) : (b)) -	m->seq = dev->seq++; -	m->len = sizeof(struct w1_netlink_msg); - -	memcpy(w, msg, sizeof(struct w1_netlink_msg)); +/* Bundle together everything required to process a request in one memory + * allocation. + */ +struct w1_cb_block { +	atomic_t refcnt; +	u32 portid; /* Sending process port ID */ +	/* maximum value for first_cn->len */ +	u16 maxlen; +	/* pointers to building up the reply message */ +	struct cn_msg *first_cn; /* fixed once the structure is populated */ +	struct cn_msg *cn; /* advances as cn_msg is appeneded */ +	struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */ +	struct w1_netlink_cmd *cmd; /* advances as cmds are appened */ +	struct w1_netlink_msg *cur_msg; /* currently message being processed */ +	/* copy of the original request follows */ +	struct cn_msg request_cn; +	/* followed by variable length: +	 * cn_msg, data (w1_netlink_msg and w1_netlink_cmd) +	 * one or more struct w1_cb_node +	 * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd) +	 */ +}; +struct w1_cb_node { +	struct w1_async_cmd async; +	/* pointers within w1_cb_block and cn data */ +	struct w1_cb_block *block; +	struct w1_netlink_msg *msg; +	struct w1_slave *sl; +	struct w1_master *dev; +}; -	cn_netlink_send(m, 0, GFP_KERNEL); +/** + * w1_reply_len() - calculate current reply length, compare to maxlen + * @block: block to calculate + * + * Calculates the current message length including possible multiple + * cn_msg and data, excludes the first sizeof(struct cn_msg).  Direclty + * compariable to maxlen and usable to send the message. + */ +static u16 w1_reply_len(struct w1_cb_block *block) +{ +	if (!block->cn) +		return 0; +	return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;  } -static void w1_send_slave(struct w1_master *dev, u64 rn) +static void w1_unref_block(struct w1_cb_block *block)  { -	struct cn_msg *msg = dev->priv; -	struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); -	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); -	int avail; - -	/* update kernel slave list */ -	w1_slave_found(dev, rn); +	if (atomic_sub_return(1, &block->refcnt) == 0) { +		u16 len = w1_reply_len(block); +		if (len) { +			cn_netlink_send_mult(block->first_cn, len, +				block->portid, 0, GFP_KERNEL); +		} +		kfree(block); +	} +} -	avail = dev->priv_size - cmd->len; +/** + * w1_reply_make_space() - send message if needed to make space + * @block: block to make space on + * @space: how many bytes requested + * + * Verify there is enough room left for the caller to add "space" bytes to the + * message, if there isn't send the message and reset. + */ +static void w1_reply_make_space(struct w1_cb_block *block, u16 space) +{ +	u16 len = w1_reply_len(block); +	if (len + space >= block->maxlen) { +		cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL); +		block->first_cn->len = 0; +		block->cn = NULL; +		block->msg = NULL; +		block->cmd = NULL; +	} +} -	if (avail > 8) { -		u64 *data = (void *)(cmd + 1) + cmd->len; +/* Early send when replies aren't bundled. */ +static void w1_netlink_check_send(struct w1_cb_block *block) +{ +	if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn) +		w1_reply_make_space(block, block->maxlen); +} -		*data = rn; -		cmd->len += 8; -		hdr->len += 8; -		msg->len += 8; -		return; +/** + * w1_netlink_setup_msg() - prepare to write block->msg + * @block: block to operate on + * @ack: determines if cn can be reused + * + * block->cn will be setup with the correct ack, advancing if needed + * block->cn->len does not include space for block->msg + * block->msg advances but remains uninitialized + */ +static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack) +{ +	if (block->cn && block->cn->ack == ack) { +		block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len); +	} else { +		/* advance or set to data */ +		if (block->cn) +			block->cn = (struct cn_msg *)(block->cn->data + +				block->cn->len); +		else +			block->cn = block->first_cn; + +		memcpy(block->cn, &block->request_cn, sizeof(*block->cn)); +		block->cn->len = 0; +		block->cn->ack = ack; +		block->msg = (struct w1_netlink_msg *)block->cn->data;  	} +} -	msg->ack++; -	cn_netlink_send(msg, 0, GFP_KERNEL); +/* Append cmd to msg, include cmd->data as well.  This is because + * any following data goes with the command and in the case of a read is + * the results. + */ +static void w1_netlink_queue_cmd(struct w1_cb_block *block, +	struct w1_netlink_cmd *cmd) +{ +	u32 space; +	w1_reply_make_space(block, sizeof(struct cn_msg) + +		sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len); + +	/* There's a status message sent after each command, so no point +	 * in trying to bundle this cmd after an existing one, because +	 * there won't be one.  Allocate and copy over a new cn_msg. +	 */ +	w1_netlink_setup_msg(block, block->request_cn.seq + 1); +	memcpy(block->msg, block->cur_msg, sizeof(*block->msg)); +	block->cn->len += sizeof(*block->msg); +	block->msg->len = 0; +	block->cmd = (struct w1_netlink_cmd *)(block->msg->data); + +	space = sizeof(*cmd) + cmd->len; +	if (block->cmd != cmd) +		memcpy(block->cmd, cmd, space); +	block->cn->len += space; +	block->msg->len += space; +} -	msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); -	hdr->len = sizeof(struct w1_netlink_cmd); -	cmd->len = 0; +/* Append req_msg and req_cmd, no other commands and no data from req_cmd are + * copied. + */ +static void w1_netlink_queue_status(struct w1_cb_block *block, +	struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd, +	int error) +{ +	u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd); +	w1_reply_make_space(block, space); +	w1_netlink_setup_msg(block, block->request_cn.ack); + +	memcpy(block->msg, req_msg, sizeof(*req_msg)); +	block->cn->len += sizeof(*req_msg); +	block->msg->len = 0; +	block->msg->status = (u8)-error; +	if (req_cmd) { +		struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data; +		memcpy(cmd, req_cmd, sizeof(*cmd)); +		block->cn->len += sizeof(*cmd); +		block->msg->len += sizeof(*cmd); +		cmd->len = 0; +	} +	w1_netlink_check_send(block);  } -static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, -		unsigned int avail) +/** + * w1_netlink_send_error() - sends the error message now + * @cn: original cn_msg + * @msg: original w1_netlink_msg + * @portid: where to send it + * @error: error status + * + * Use when a block isn't available to queue the message to and cn, msg + * might not be contiguous. + */ +static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, +	int portid, int error)  { -	struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); -	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); -	int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH; +	struct { +		struct cn_msg cn; +		struct w1_netlink_msg msg; +	} packet; +	memcpy(&packet.cn, cn, sizeof(packet.cn)); +	memcpy(&packet.msg, msg, sizeof(packet.msg)); +	packet.cn.len = sizeof(packet.msg); +	packet.msg.len = 0; +	packet.msg.status = (u8)-error; +	cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL); +} -	dev->priv = msg; -	dev->priv_size = avail; +/** + * w1_netlink_send() - sends w1 netlink notifications + * @dev: w1_master the even is associated with or for + * @msg: w1_netlink_msg message to be sent + * + * This are notifications generated from the kernel. + */ +void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) +{ +	struct { +		struct cn_msg cn; +		struct w1_netlink_msg msg; +	} packet; +	memset(&packet, 0, sizeof(packet)); -	w1_search_process_cb(dev, search_type, w1_send_slave); +	packet.cn.id.idx = CN_W1_IDX; +	packet.cn.id.val = CN_W1_VAL; -	msg->ack = 0; -	cn_netlink_send(msg, 0, GFP_KERNEL); +	packet.cn.seq = dev->seq++; +	packet.cn.len = sizeof(*msg); -	dev->priv = NULL; -	dev->priv_size = 0; +	memcpy(&packet.msg, msg, sizeof(*msg)); +	packet.msg.len = 0; -	return 0; +	cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);  } -static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, -		struct w1_netlink_cmd *cmd) +static void w1_send_slave(struct w1_master *dev, u64 rn)  { -	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; +	struct w1_cb_block *block = dev->priv; +	struct w1_netlink_cmd *cache_cmd = block->cmd; +	u64 *data; -	cm = (struct cn_msg *)(data); -	h = (struct w1_netlink_msg *)(cm + 1); -	c = (struct w1_netlink_cmd *)(h + 1); +	w1_reply_make_space(block, sizeof(*data)); -	memcpy(cm, msg, sizeof(struct cn_msg)); -	memcpy(h, hdr, sizeof(struct w1_netlink_msg)); -	memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); +	/* Add cmd back if the packet was sent */ +	if (!block->cmd) { +		cache_cmd->len = 0; +		w1_netlink_queue_cmd(block, cache_cmd); +	} -	cm->ack = msg->seq+1; -	cm->len = sizeof(struct w1_netlink_msg) + -		sizeof(struct w1_netlink_cmd) + cmd->len; +	data = (u64 *)(block->cmd->data + block->cmd->len); -	h->len = sizeof(struct w1_netlink_cmd) + cmd->len; +	*data = rn; +	block->cn->len += sizeof(*data); +	block->msg->len += sizeof(*data); +	block->cmd->len += sizeof(*data); +} -	memcpy(c->data, cmd->data, c->len); +static void w1_found_send_slave(struct w1_master *dev, u64 rn) +{ +	/* update kernel slave list */ +	w1_slave_found(dev, rn); -	err = cn_netlink_send(cm, 0, GFP_KERNEL); +	w1_send_slave(dev, rn); +} -	kfree(data); +/* Get the current slave list, or search (with or without alarm) */ +static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd) +{ +	struct w1_slave *sl; -	return err; +	req_cmd->len = 0; +	w1_netlink_queue_cmd(dev->priv, req_cmd); + +	if (req_cmd->cmd == W1_CMD_LIST_SLAVES) { +		u64 rn; +		mutex_lock(&dev->list_mutex); +		list_for_each_entry(sl, &dev->slist, w1_slave_entry) { +			memcpy(&rn, &sl->reg_num, sizeof(rn)); +			w1_send_slave(dev, rn); +		} +		mutex_unlock(&dev->list_mutex); +	} else { +		w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ? +			W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave); +	} + +	return 0;  } -static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, -		struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) +static int w1_process_command_io(struct w1_master *dev, +	struct w1_netlink_cmd *cmd)  {  	int err = 0;  	switch (cmd->cmd) {  	case W1_CMD_TOUCH:  		w1_touch_block(dev, cmd->data, cmd->len); -		w1_send_read_reply(msg, hdr, cmd); +		w1_netlink_queue_cmd(dev->priv, cmd);  		break;  	case W1_CMD_READ:  		w1_read_block(dev, cmd->data, cmd->len); -		w1_send_read_reply(msg, hdr, cmd); +		w1_netlink_queue_cmd(dev->priv, cmd);  		break;  	case W1_CMD_WRITE:  		w1_write_block(dev, cmd->data, cmd->len); @@ -163,79 +329,97 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,  	return err;  } -static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, -		struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) +static int w1_process_command_addremove(struct w1_master *dev, +	struct w1_netlink_cmd *cmd)  { -	int err = -EINVAL; -	struct cn_msg *msg; -	struct w1_netlink_msg *hdr; -	struct w1_netlink_cmd *cmd; +	struct w1_slave *sl; +	int err = 0; +	struct w1_reg_num *id; -	msg = kzalloc(PAGE_SIZE, GFP_KERNEL); -	if (!msg) -		return -ENOMEM; +	if (cmd->len != sizeof(*id)) +		return -EINVAL; -	msg->id = req_msg->id; -	msg->seq = req_msg->seq; -	msg->ack = 0; -	msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); +	id = (struct w1_reg_num *)cmd->data; -	hdr = (struct w1_netlink_msg *)(msg + 1); -	cmd = (struct w1_netlink_cmd *)(hdr + 1); +	sl = w1_slave_search_device(dev, id); +	switch (cmd->cmd) { +	case W1_CMD_SLAVE_ADD: +		if (sl) +			err = -EINVAL; +		else +			err = w1_attach_slave_device(dev, id); +		break; +	case W1_CMD_SLAVE_REMOVE: +		if (sl) +			w1_slave_detach(sl); +		else +			err = -EINVAL; +		break; +	default: +		err = -EINVAL; +		break; +	} -	hdr->type = W1_MASTER_CMD; -	hdr->id = req_hdr->id; -	hdr->len = sizeof(struct w1_netlink_cmd); +	return err; +} -	cmd->cmd = req_cmd->cmd; -	cmd->len = 0; +static int w1_process_command_master(struct w1_master *dev, +	struct w1_netlink_cmd *req_cmd) +{ +	int err = -EINVAL; -	switch (cmd->cmd) { +	/* drop bus_mutex for search (does it's own locking), and add/remove +	 * which doesn't use the bus +	 */ +	switch (req_cmd->cmd) {  	case W1_CMD_SEARCH:  	case W1_CMD_ALARM_SEARCH: -		err = w1_process_search_command(dev, msg, -				PAGE_SIZE - msg->len - sizeof(struct cn_msg)); +	case W1_CMD_LIST_SLAVES: +		mutex_unlock(&dev->bus_mutex); +		err = w1_get_slaves(dev, req_cmd); +		mutex_lock(&dev->bus_mutex);  		break;  	case W1_CMD_READ:  	case W1_CMD_WRITE:  	case W1_CMD_TOUCH: -		err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); +		err = w1_process_command_io(dev, req_cmd);  		break;  	case W1_CMD_RESET:  		err = w1_reset_bus(dev);  		break; +	case W1_CMD_SLAVE_ADD: +	case W1_CMD_SLAVE_REMOVE: +		mutex_unlock(&dev->bus_mutex); +		mutex_lock(&dev->mutex); +		err = w1_process_command_addremove(dev, req_cmd); +		mutex_unlock(&dev->mutex); +		mutex_lock(&dev->bus_mutex); +		break;  	default:  		err = -EINVAL;  		break;  	} -	kfree(msg);  	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) +static int w1_process_command_slave(struct w1_slave *sl, +		struct w1_netlink_cmd *cmd)  {  	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); -	return w1_process_command_io(sl->master, msg, hdr, cmd); +	return w1_process_command_io(sl->master, cmd);  } -static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) +static int w1_process_command_root(struct cn_msg *req_cn, u32 portid)  { -	struct w1_master *m; +	struct w1_master *dev;  	struct cn_msg *cn; -	struct w1_netlink_msg *w; +	struct w1_netlink_msg *msg;  	u32 *id; -	if (mcmd->type != W1_LIST_MASTERS) { -		printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", -			__func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); -		return -EPROTO; -	} -  	cn = kmalloc(PAGE_SIZE, GFP_KERNEL);  	if (!cn)  		return -ENOMEM; @@ -243,108 +427,264 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc  	cn->id.idx = CN_W1_IDX;  	cn->id.val = CN_W1_VAL; -	cn->seq = msg->seq; -	cn->ack = 1; +	cn->seq = req_cn->seq; +	cn->ack = req_cn->seq + 1;  	cn->len = sizeof(struct w1_netlink_msg); -	w = (struct w1_netlink_msg *)(cn + 1); +	msg = (struct w1_netlink_msg *)cn->data; -	w->type = W1_LIST_MASTERS; -	w->status = 0; -	w->len = 0; -	id = (u32 *)(w + 1); +	msg->type = W1_LIST_MASTERS; +	msg->status = 0; +	msg->len = 0; +	id = (u32 *)msg->data;  	mutex_lock(&w1_mlock); -	list_for_each_entry(m, &w1_masters, w1_master_entry) { +	list_for_each_entry(dev, &w1_masters, w1_master_entry) {  		if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { -			cn_netlink_send(cn, 0, GFP_KERNEL); -			cn->ack++; +			cn_netlink_send(cn, portid, 0, GFP_KERNEL);  			cn->len = sizeof(struct w1_netlink_msg); -			w->len = 0; -			id = (u32 *)(w + 1); +			msg->len = 0; +			id = (u32 *)msg->data;  		} -		*id = m->id; -		w->len += sizeof(*id); +		*id = dev->id; +		msg->len += sizeof(*id);  		cn->len += sizeof(*id);  		id++;  	} -	cn->ack = 0; -	cn_netlink_send(cn, 0, GFP_KERNEL); +	cn_netlink_send(cn, portid, 0, GFP_KERNEL);  	mutex_unlock(&w1_mlock);  	kfree(cn);  	return 0;  } -static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, -		struct w1_netlink_cmd *rcmd, int error) +static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)  { -	struct cn_msg *cmsg; -	struct w1_netlink_msg *msg; -	struct w1_netlink_cmd *cmd; +	struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node, +		async); +	u16 mlen = node->msg->len; +	u16 len; +	int err = 0; +	struct w1_slave *sl = node->sl; +	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data; -	cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); -	if (!cmsg) -		return -ENOMEM; +	mutex_lock(&dev->bus_mutex); +	dev->priv = node->block; +	if (sl && w1_reset_select_slave(sl)) +		err = -ENODEV; +	node->block->cur_msg = node->msg; -	msg = (struct w1_netlink_msg *)(cmsg + 1); -	cmd = (struct w1_netlink_cmd *)(msg + 1); +	while (mlen && !err) { +		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { +			err = -E2BIG; +			break; +		} -	memcpy(cmsg, rcmsg, sizeof(*cmsg)); -	cmsg->len = sizeof(*msg); +		if (sl) +			err = w1_process_command_slave(sl, cmd); +		else +			err = w1_process_command_master(dev, cmd); +		w1_netlink_check_send(node->block); -	memcpy(msg, rmsg, sizeof(*msg)); -	msg->len = 0; -	msg->status = (short)-error; +		w1_netlink_queue_status(node->block, node->msg, cmd, err); +		err = 0; -	if (rcmd) { -		memcpy(cmd, rcmd, sizeof(*cmd)); -		cmd->len = 0; -		msg->len += sizeof(*cmd); -		cmsg->len += sizeof(*cmd); +		len = sizeof(*cmd) + cmd->len; +		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len); +		mlen -= len;  	} -	error = cn_netlink_send(cmsg, 0, GFP_KERNEL); -	kfree(cmsg); +	if (!cmd || err) +		w1_netlink_queue_status(node->block, node->msg, cmd, err); + +	/* ref taken in w1_search_slave or w1_search_master_id when building +	 * the block +	 */ +	if (sl) +		w1_unref_slave(sl); +	else +		atomic_dec(&dev->refcnt); +	dev->priv = NULL; +	mutex_unlock(&dev->bus_mutex); + +	mutex_lock(&dev->list_mutex); +	list_del(&async_cmd->async_entry); +	mutex_unlock(&dev->list_mutex); -	return error; +	w1_unref_block(node->block);  } -static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) +static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count, +	u16 *slave_len)  { -	struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); -	struct w1_netlink_cmd *cmd; +	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data; +	u16 mlen = msg->len; +	u16 len; +	int slave_list = 0; +	while (mlen) { +		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) +			break; + +		switch (cmd->cmd) { +		case W1_CMD_SEARCH: +		case W1_CMD_ALARM_SEARCH: +		case W1_CMD_LIST_SLAVES: +			++slave_list; +		} +		++*cmd_count; +		len = sizeof(*cmd) + cmd->len; +		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len); +		mlen -= len; +	} + +	if (slave_list) { +		struct w1_master *dev = w1_search_master_id(msg->id.mst.id); +		if (dev) { +			/* Bytes, and likely an overstimate, and if it isn't +			 * the results can still be split between packets. +			 */ +			*slave_len += sizeof(struct w1_reg_num) * slave_list * +				(dev->slave_count + dev->max_slave_count); +			/* search incremented it */ +			atomic_dec(&dev->refcnt); +		} +	} +} + +static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp) +{ +	struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1);  	struct w1_slave *sl;  	struct w1_master *dev; +	u16 msg_len; +	u16 slave_len = 0;  	int err = 0; +	struct w1_cb_block *block = NULL; +	struct w1_cb_node *node = NULL; +	int node_count = 0; +	int cmd_count = 0; + +	/* If any unknown flag is set let the application know, that way +	 * applications can detect the absence of features in kernels that +	 * don't know about them.  http://lwn.net/Articles/587527/ +	 */ +	if (cn->flags & ~(W1_CN_BUNDLE)) { +		w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL); +		return; +	} + +	/* Count the number of master or slave commands there are to allocate +	 * space for one cb_node each. +	 */ +	msg_len = cn->len; +	while (msg_len && !err) { +		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) { +			err = -E2BIG; +			break; +		} -	while (msg->len && !err) { -		struct w1_reg_num id; -		u16 mlen = m->len; -		u8 *cmd_data = m->data; +		/* count messages for nodes and allocate any additional space +		 * required for slave lists +		 */ +		if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) { +			++node_count; +			w1_list_count_cmds(msg, &cmd_count, &slave_len); +		} + +		msg_len -= sizeof(struct w1_netlink_msg) + msg->len; +		msg = (struct w1_netlink_msg *)(((u8 *)msg) + +			sizeof(struct w1_netlink_msg) + msg->len); +	} +	msg = (struct w1_netlink_msg *)(cn + 1); +	if (node_count) { +		int size; +		u16 reply_size = sizeof(*cn) + cn->len + slave_len; +		if (cn->flags & W1_CN_BUNDLE) { +			/* bundling duplicats some of the messages */ +			reply_size += 2 * cmd_count * (sizeof(struct cn_msg) + +				sizeof(struct w1_netlink_msg) + +				sizeof(struct w1_netlink_cmd)); +		} +		reply_size = MIN(CONNECTOR_MAX_MSG_SIZE, reply_size); + +		/* allocate space for the block, a copy of the original message, +		 * one node per cmd to point into the original message, +		 * space for replies which is the original message size plus +		 * space for any list slave data and status messages +		 * cn->len doesn't include itself which is part of the block +		 * */ +		size =  /* block + original message */ +			sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len + +			/* space for nodes */ +			node_count * sizeof(struct w1_cb_node) + +			/* replies */ +			sizeof(struct cn_msg) + reply_size; +		block = kzalloc(size, GFP_KERNEL); +		if (!block) { +			/* if the system is already out of memory, +			 * (A) will this work, and (B) would it be better +			 * to not try? +			 */ +			w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM); +			return; +		} +		atomic_set(&block->refcnt, 1); +		block->portid = nsp->portid; +		memcpy(&block->request_cn, cn, sizeof(*cn) + cn->len); +		node = (struct w1_cb_node *)(block->request_cn.data + cn->len); + +		/* Sneeky, when not bundling, reply_size is the allocated space +		 * required for the reply, cn_msg isn't part of maxlen so +		 * it should be reply_size - sizeof(struct cn_msg), however +		 * when checking if there is enough space, w1_reply_make_space +		 * is called with the full message size including cn_msg, +		 * because it isn't known at that time if an additional cn_msg +		 * will need to be allocated.  So an extra cn_msg is added +		 * above in "size". +		 */ +		block->maxlen = reply_size; +		block->first_cn = (struct cn_msg *)(node + node_count); +		memset(block->first_cn, 0, sizeof(*block->first_cn)); +	} + +	msg_len = cn->len; +	while (msg_len && !err) {  		dev = NULL;  		sl = NULL; -		cmd = 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) { +		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {  			err = -E2BIG;  			break;  		} -		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); +		/* execute on this thread, no need to process later */ +		if (msg->type == W1_LIST_MASTERS) { +			err = w1_process_command_root(cn, nsp->portid); +			goto out_cont; +		} + +		/* All following message types require additional data, +		 * check here before references are taken. +		 */ +		if (!msg->len) { +			err = -EPROTO; +			goto out_cont; +		} + +		/* both search calls take references */ +		if (msg->type == W1_MASTER_CMD) { +			dev = w1_search_master_id(msg->id.mst.id); +		} else if (msg->type == W1_SLAVE_CMD) { +			sl = w1_search_slave((struct w1_reg_num *)msg->id.id);  			if (sl)  				dev = sl->master;  		} else { -			err = w1_process_command_root(msg, m); +			printk(KERN_NOTICE +				"%s: cn: %x.%x, wrong type: %u, len: %u.\n", +				__func__, cn->id.idx, cn->id.val, +				msg->type, msg->len); +			err = -EPROTO;  			goto out_cont;  		} @@ -354,45 +694,31 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)  		}  		err = 0; -		if (!mlen) -			goto out_cont; - -		mutex_lock(&dev->mutex); -		if (sl && w1_reset_select_slave(sl)) { -			err = -ENODEV; -			goto out_up; -		} +		atomic_inc(&block->refcnt); +		node->async.cb = w1_process_cb; +		node->block = block; +		node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn + +			(size_t)((u8 *)msg - (u8 *)cn)); +		node->sl = sl; +		node->dev = dev; -		while (mlen) { -			cmd = (struct w1_netlink_cmd *)cmd_data; +		mutex_lock(&dev->list_mutex); +		list_add_tail(&node->async.async_entry, &dev->async_list); +		wake_up_process(dev->thread); +		mutex_unlock(&dev->list_mutex); +		++node; -			if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { -				err = -E2BIG; -				break; -			} - -			if (sl) -				err = w1_process_command_slave(sl, msg, m, cmd); -			else -				err = w1_process_command_master(dev, msg, m, cmd); - -			w1_netlink_send_error(msg, m, cmd, err); -			err = 0; - -			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); -		mutex_unlock(&dev->mutex);  out_cont: -		if (!cmd || err) -			w1_netlink_send_error(msg, m, cmd, err); -		msg->len -= sizeof(struct w1_netlink_msg) + m->len; -		m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); +		/* Can't queue because that modifies block and another +		 * thread could be processing the messages by now and +		 * there isn't a lock, send directly. +		 */ +		if (err) +			w1_netlink_send_error(cn, msg, nsp->portid, err); +		msg_len -= sizeof(struct w1_netlink_msg) + msg->len; +		msg = (struct w1_netlink_msg *)(((u8 *)msg) + +			sizeof(struct w1_netlink_msg) + msg->len);  		/*  		 * Let's allow requests for nonexisting devices. @@ -400,6 +726,8 @@ out_cont:  		if (err == -ENODEV)  			err = 0;  	} +	if (block) +		w1_unref_block(block);  }  int w1_init_netlink(void) @@ -416,7 +744,7 @@ void w1_fini_netlink(void)  	cn_del_callback(&w1_id);  }  #else -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 *cn)  {  } diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index b0922dc2965..c99a9ce05e6 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h @@ -27,6 +27,29 @@  #include "w1.h" +/** + * enum w1_cn_msg_flags - bitfield flags for struct cn_msg.flags + * + * @W1_CN_BUNDLE: Request bundling replies into fewer messagse.  Be prepared + * to handle multiple struct cn_msg, struct w1_netlink_msg, and + * struct w1_netlink_cmd in one packet. + */ +enum w1_cn_msg_flags { +	W1_CN_BUNDLE = 1, +}; + +/** + * enum w1_netlink_message_types - message type + * + * @W1_SLAVE_ADD: notification that a slave device was added + * @W1_SLAVE_REMOVE: notification that a slave device was removed + * @W1_MASTER_ADD: notification that a new bus master was added + * @W1_MASTER_REMOVE: notification that a bus masterwas removed + * @W1_MASTER_CMD: initiate operations on a specific master + * @W1_SLAVE_CMD: sends reset, selects the slave, then does a read/write/touch + * operation + * @W1_LIST_MASTERS: used to determine the bus master identifiers + */  enum w1_netlink_message_types {  	W1_SLAVE_ADD = 0,  	W1_SLAVE_REMOVE, @@ -37,6 +60,19 @@ enum w1_netlink_message_types {  	W1_LIST_MASTERS,  }; +/** + * struct w1_netlink_msg - holds w1 message type, id, and result + * + * @type: one of enum w1_netlink_message_types + * @status: kernel feedback for success 0 or errno failure value + * @len: length of data following w1_netlink_msg + * @id: union holding master bus id (msg.id) and slave device id (id[8]). + * @data: start address of any following data + * + * The base message structure for w1 messages over netlink. + * The netlink connector data sequence is, struct nlmsghdr, struct cn_msg, + * then one or more struct w1_netlink_msg (each with optional data). + */  struct w1_netlink_msg  {  	__u8				type; @@ -52,6 +88,23 @@ struct w1_netlink_msg  	__u8				data[0];  }; +/** + * enum w1_commands - commands available for master or slave operations + * + * @W1_CMD_READ: read len bytes + * @W1_CMD_WRITE: write len bytes + * @W1_CMD_SEARCH: initiate a standard search, returns only the slave + * devices found during that search + * @W1_CMD_ALARM_SEARCH: search for devices that are currently alarming + * @W1_CMD_TOUCH: Touches a series of bytes. + * @W1_CMD_RESET: sends a bus reset on the given master + * @W1_CMD_SLAVE_ADD: adds a slave to the given master, + * 8 byte slave id at data[0] + * @W1_CMD_SLAVE_REMOVE: removes a slave to the given master, + * 8 byte slave id at data[0] + * @W1_CMD_LIST_SLAVES: list of slaves registered on this master + * @W1_CMD_MAX: number of available commands + */  enum w1_commands {  	W1_CMD_READ = 0,  	W1_CMD_WRITE, @@ -59,9 +112,23 @@ enum w1_commands {  	W1_CMD_ALARM_SEARCH,  	W1_CMD_TOUCH,  	W1_CMD_RESET, -	W1_CMD_MAX, +	W1_CMD_SLAVE_ADD, +	W1_CMD_SLAVE_REMOVE, +	W1_CMD_LIST_SLAVES, +	W1_CMD_MAX  }; +/** + * struct w1_netlink_cmd - holds the command and data + * + * @cmd: one of enum w1_commands + * @res: reserved + * @len: length of data following w1_netlink_cmd + * @data: start address of any following data + * + * One or more struct w1_netlink_cmd is placed starting at w1_netlink_msg.data + * each with optional data. + */  struct w1_netlink_cmd  {  	__u8				cmd;  | 
