xref: /linux/drivers/w1/masters/ds2490.c (revision e464af24734c40853dd68ec694d83a82e3930d66)
181f6075eSEvgeniy Polyakov /*
281f6075eSEvgeniy Polyakov  *	dscore.c
381f6075eSEvgeniy Polyakov  *
481f6075eSEvgeniy Polyakov  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
581f6075eSEvgeniy Polyakov  *
681f6075eSEvgeniy Polyakov  *
781f6075eSEvgeniy Polyakov  * This program is free software; you can redistribute it and/or modify
881f6075eSEvgeniy Polyakov  * it under the terms of the GNU General Public License as published by
981f6075eSEvgeniy Polyakov  * the Free Software Foundation; either version 2 of the License, or
1081f6075eSEvgeniy Polyakov  * (at your option) any later version.
1181f6075eSEvgeniy Polyakov  *
1281f6075eSEvgeniy Polyakov  * This program is distributed in the hope that it will be useful,
1381f6075eSEvgeniy Polyakov  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1481f6075eSEvgeniy Polyakov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1581f6075eSEvgeniy Polyakov  * GNU General Public License for more details.
1681f6075eSEvgeniy Polyakov  *
1781f6075eSEvgeniy Polyakov  * You should have received a copy of the GNU General Public License
1881f6075eSEvgeniy Polyakov  * along with this program; if not, write to the Free Software
1981f6075eSEvgeniy Polyakov  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2081f6075eSEvgeniy Polyakov  */
2181f6075eSEvgeniy Polyakov 
2281f6075eSEvgeniy Polyakov #include <linux/module.h>
2381f6075eSEvgeniy Polyakov #include <linux/kernel.h>
2481f6075eSEvgeniy Polyakov #include <linux/mod_devicetable.h>
2581f6075eSEvgeniy Polyakov #include <linux/usb.h>
2681f6075eSEvgeniy Polyakov 
2781f6075eSEvgeniy Polyakov #include "../w1_int.h"
2881f6075eSEvgeniy Polyakov #include "../w1.h"
2981f6075eSEvgeniy Polyakov 
3081f6075eSEvgeniy Polyakov /* COMMAND TYPE CODES */
3181f6075eSEvgeniy Polyakov #define CONTROL_CMD			0x00
3281f6075eSEvgeniy Polyakov #define COMM_CMD			0x01
3381f6075eSEvgeniy Polyakov #define MODE_CMD			0x02
3481f6075eSEvgeniy Polyakov 
3581f6075eSEvgeniy Polyakov /* CONTROL COMMAND CODES */
3681f6075eSEvgeniy Polyakov #define CTL_RESET_DEVICE		0x0000
3781f6075eSEvgeniy Polyakov #define CTL_START_EXE			0x0001
3881f6075eSEvgeniy Polyakov #define CTL_RESUME_EXE			0x0002
3981f6075eSEvgeniy Polyakov #define CTL_HALT_EXE_IDLE		0x0003
4081f6075eSEvgeniy Polyakov #define CTL_HALT_EXE_DONE		0x0004
4181f6075eSEvgeniy Polyakov #define CTL_FLUSH_COMM_CMDS		0x0007
4281f6075eSEvgeniy Polyakov #define CTL_FLUSH_RCV_BUFFER		0x0008
4381f6075eSEvgeniy Polyakov #define CTL_FLUSH_XMT_BUFFER		0x0009
4481f6075eSEvgeniy Polyakov #define CTL_GET_COMM_CMDS		0x000A
4581f6075eSEvgeniy Polyakov 
4681f6075eSEvgeniy Polyakov /* MODE COMMAND CODES */
4781f6075eSEvgeniy Polyakov #define MOD_PULSE_EN			0x0000
4881f6075eSEvgeniy Polyakov #define MOD_SPEED_CHANGE_EN		0x0001
4981f6075eSEvgeniy Polyakov #define MOD_1WIRE_SPEED			0x0002
5081f6075eSEvgeniy Polyakov #define MOD_STRONG_PU_DURATION		0x0003
5181f6075eSEvgeniy Polyakov #define MOD_PULLDOWN_SLEWRATE		0x0004
5281f6075eSEvgeniy Polyakov #define MOD_PROG_PULSE_DURATION		0x0005
5381f6075eSEvgeniy Polyakov #define MOD_WRITE1_LOWTIME		0x0006
5481f6075eSEvgeniy Polyakov #define MOD_DSOW0_TREC			0x0007
5581f6075eSEvgeniy Polyakov 
5681f6075eSEvgeniy Polyakov /* COMMUNICATION COMMAND CODES */
5781f6075eSEvgeniy Polyakov #define COMM_ERROR_ESCAPE		0x0601
5881f6075eSEvgeniy Polyakov #define COMM_SET_DURATION		0x0012
5981f6075eSEvgeniy Polyakov #define COMM_BIT_IO			0x0020
6081f6075eSEvgeniy Polyakov #define COMM_PULSE			0x0030
6181f6075eSEvgeniy Polyakov #define COMM_1_WIRE_RESET		0x0042
6281f6075eSEvgeniy Polyakov #define COMM_BYTE_IO			0x0052
6381f6075eSEvgeniy Polyakov #define COMM_MATCH_ACCESS		0x0064
6481f6075eSEvgeniy Polyakov #define COMM_BLOCK_IO			0x0074
6581f6075eSEvgeniy Polyakov #define COMM_READ_STRAIGHT		0x0080
6681f6075eSEvgeniy Polyakov #define COMM_DO_RELEASE			0x6092
6781f6075eSEvgeniy Polyakov #define COMM_SET_PATH			0x00A2
6881f6075eSEvgeniy Polyakov #define COMM_WRITE_SRAM_PAGE		0x00B2
6981f6075eSEvgeniy Polyakov #define COMM_WRITE_EPROM		0x00C4
7081f6075eSEvgeniy Polyakov #define COMM_READ_CRC_PROT_PAGE		0x00D4
7181f6075eSEvgeniy Polyakov #define COMM_READ_REDIRECT_PAGE_CRC	0x21E4
7281f6075eSEvgeniy Polyakov #define COMM_SEARCH_ACCESS		0x00F4
7381f6075eSEvgeniy Polyakov 
7481f6075eSEvgeniy Polyakov /* Communication command bits */
7581f6075eSEvgeniy Polyakov #define COMM_TYPE			0x0008
7681f6075eSEvgeniy Polyakov #define COMM_SE				0x0008
7781f6075eSEvgeniy Polyakov #define COMM_D				0x0008
7881f6075eSEvgeniy Polyakov #define COMM_Z				0x0008
7981f6075eSEvgeniy Polyakov #define COMM_CH				0x0008
8081f6075eSEvgeniy Polyakov #define COMM_SM				0x0008
8181f6075eSEvgeniy Polyakov #define COMM_R				0x0008
8281f6075eSEvgeniy Polyakov #define COMM_IM				0x0001
8381f6075eSEvgeniy Polyakov 
8481f6075eSEvgeniy Polyakov #define COMM_PS				0x4000
8581f6075eSEvgeniy Polyakov #define COMM_PST			0x4000
8681f6075eSEvgeniy Polyakov #define COMM_CIB			0x4000
8781f6075eSEvgeniy Polyakov #define COMM_RTS			0x4000
8881f6075eSEvgeniy Polyakov #define COMM_DT				0x2000
8981f6075eSEvgeniy Polyakov #define COMM_SPU			0x1000
9081f6075eSEvgeniy Polyakov #define COMM_F				0x0800
9181f6075eSEvgeniy Polyakov #define COMM_NTP			0x0400
9281f6075eSEvgeniy Polyakov #define COMM_ICP			0x0200
9381f6075eSEvgeniy Polyakov #define COMM_RST			0x0100
9481f6075eSEvgeniy Polyakov 
9581f6075eSEvgeniy Polyakov #define PULSE_PROG			0x01
9681f6075eSEvgeniy Polyakov #define PULSE_SPUE			0x02
9781f6075eSEvgeniy Polyakov 
9881f6075eSEvgeniy Polyakov #define BRANCH_MAIN			0xCC
9981f6075eSEvgeniy Polyakov #define BRANCH_AUX			0x33
10081f6075eSEvgeniy Polyakov 
10181f6075eSEvgeniy Polyakov /* Status flags */
10281f6075eSEvgeniy Polyakov #define ST_SPUA				0x01  /* Strong Pull-up is active */
10381f6075eSEvgeniy Polyakov #define ST_PRGA				0x02  /* 12V programming pulse is being generated */
10481f6075eSEvgeniy Polyakov #define ST_12VP				0x04  /* external 12V programming voltage is present */
10581f6075eSEvgeniy Polyakov #define ST_PMOD				0x08  /* DS2490 powered from USB and external sources */
10681f6075eSEvgeniy Polyakov #define ST_HALT				0x10  /* DS2490 is currently halted */
10781f6075eSEvgeniy Polyakov #define ST_IDLE				0x20  /* DS2490 is currently idle */
10881f6075eSEvgeniy Polyakov #define ST_EPOF				0x80
10981f6075eSEvgeniy Polyakov 
1104b9cf1bcSDavid Fries /* Result Register flags */
1114b9cf1bcSDavid Fries #define RR_DETECT			0xA5 /* New device detected */
1124b9cf1bcSDavid Fries #define RR_NRS				0x01 /* Reset no presence or ... */
1134b9cf1bcSDavid Fries #define RR_SH				0x02 /* short on reset or set path */
1144b9cf1bcSDavid Fries #define RR_APP				0x04 /* alarming presence on reset */
1154b9cf1bcSDavid Fries #define RR_VPP				0x08 /* 12V expected not seen */
1164b9cf1bcSDavid Fries #define RR_CMP				0x10 /* compare error */
1174b9cf1bcSDavid Fries #define RR_CRC				0x20 /* CRC error detected */
1184b9cf1bcSDavid Fries #define RR_RDP				0x40 /* redirected page */
1194b9cf1bcSDavid Fries #define RR_EOS				0x80 /* end of search error */
1204b9cf1bcSDavid Fries 
12181f6075eSEvgeniy Polyakov #define SPEED_NORMAL			0x00
12281f6075eSEvgeniy Polyakov #define SPEED_FLEXIBLE			0x01
12381f6075eSEvgeniy Polyakov #define SPEED_OVERDRIVE			0x02
12481f6075eSEvgeniy Polyakov 
12581f6075eSEvgeniy Polyakov #define NUM_EP				4
12681f6075eSEvgeniy Polyakov #define EP_CONTROL			0
12781f6075eSEvgeniy Polyakov #define EP_STATUS			1
12881f6075eSEvgeniy Polyakov #define EP_DATA_OUT			2
12981f6075eSEvgeniy Polyakov #define EP_DATA_IN			3
13081f6075eSEvgeniy Polyakov 
13181f6075eSEvgeniy Polyakov struct ds_device
13281f6075eSEvgeniy Polyakov {
13381f6075eSEvgeniy Polyakov 	struct list_head	ds_entry;
13481f6075eSEvgeniy Polyakov 
13581f6075eSEvgeniy Polyakov 	struct usb_device	*udev;
13681f6075eSEvgeniy Polyakov 	struct usb_interface	*intf;
13781f6075eSEvgeniy Polyakov 
13881f6075eSEvgeniy Polyakov 	int			ep[NUM_EP];
13981f6075eSEvgeniy Polyakov 
1401f4ec2d7SDavid Fries 	/* Strong PullUp
1411f4ec2d7SDavid Fries 	 * 0: pullup not active, else duration in milliseconds
1421f4ec2d7SDavid Fries 	 */
1431f4ec2d7SDavid Fries 	int			spu_sleep;
1441f4ec2d7SDavid Fries 
14581f6075eSEvgeniy Polyakov 	struct w1_bus_master	master;
14681f6075eSEvgeniy Polyakov };
14781f6075eSEvgeniy Polyakov 
14881f6075eSEvgeniy Polyakov struct ds_status
14981f6075eSEvgeniy Polyakov {
15081f6075eSEvgeniy Polyakov 	u8			enable;
15181f6075eSEvgeniy Polyakov 	u8			speed;
15281f6075eSEvgeniy Polyakov 	u8			pullup_dur;
15381f6075eSEvgeniy Polyakov 	u8			ppuls_dur;
15481f6075eSEvgeniy Polyakov 	u8			pulldown_slew;
15581f6075eSEvgeniy Polyakov 	u8			write1_time;
15681f6075eSEvgeniy Polyakov 	u8			write0_time;
15781f6075eSEvgeniy Polyakov 	u8			reserved0;
15881f6075eSEvgeniy Polyakov 	u8			status;
15981f6075eSEvgeniy Polyakov 	u8			command0;
16081f6075eSEvgeniy Polyakov 	u8			command1;
16181f6075eSEvgeniy Polyakov 	u8			command_buffer_status;
16281f6075eSEvgeniy Polyakov 	u8			data_out_buffer_status;
16381f6075eSEvgeniy Polyakov 	u8			data_in_buffer_status;
16481f6075eSEvgeniy Polyakov 	u8			reserved1;
16581f6075eSEvgeniy Polyakov 	u8			reserved2;
16681f6075eSEvgeniy Polyakov 
16781f6075eSEvgeniy Polyakov };
16881f6075eSEvgeniy Polyakov 
16981f6075eSEvgeniy Polyakov static struct usb_device_id ds_id_table [] = {
17081f6075eSEvgeniy Polyakov 	{ USB_DEVICE(0x04fa, 0x2490) },
17181f6075eSEvgeniy Polyakov 	{ },
17281f6075eSEvgeniy Polyakov };
17381f6075eSEvgeniy Polyakov MODULE_DEVICE_TABLE(usb, ds_id_table);
17481f6075eSEvgeniy Polyakov 
17581f6075eSEvgeniy Polyakov static int ds_probe(struct usb_interface *, const struct usb_device_id *);
17681f6075eSEvgeniy Polyakov static void ds_disconnect(struct usb_interface *);
17781f6075eSEvgeniy Polyakov 
17881f6075eSEvgeniy Polyakov static int ds_send_control(struct ds_device *, u16, u16);
17981f6075eSEvgeniy Polyakov static int ds_send_control_cmd(struct ds_device *, u16, u16);
18081f6075eSEvgeniy Polyakov 
18181f6075eSEvgeniy Polyakov static LIST_HEAD(ds_devices);
182abd52a13SEvgeniy Polyakov static DEFINE_MUTEX(ds_mutex);
18381f6075eSEvgeniy Polyakov 
18481f6075eSEvgeniy Polyakov static struct usb_driver ds_driver = {
18581f6075eSEvgeniy Polyakov 	.name =		"DS9490R",
18681f6075eSEvgeniy Polyakov 	.probe =	ds_probe,
18781f6075eSEvgeniy Polyakov 	.disconnect =	ds_disconnect,
18881f6075eSEvgeniy Polyakov 	.id_table =	ds_id_table,
18981f6075eSEvgeniy Polyakov };
19081f6075eSEvgeniy Polyakov 
19181f6075eSEvgeniy Polyakov static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
19281f6075eSEvgeniy Polyakov {
19381f6075eSEvgeniy Polyakov 	int err;
19481f6075eSEvgeniy Polyakov 
19581f6075eSEvgeniy Polyakov 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
19681f6075eSEvgeniy Polyakov 			CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
19781f6075eSEvgeniy Polyakov 	if (err < 0) {
19881f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
19981f6075eSEvgeniy Polyakov 				value, index, err);
20081f6075eSEvgeniy Polyakov 		return err;
20181f6075eSEvgeniy Polyakov 	}
20281f6075eSEvgeniy Polyakov 
20381f6075eSEvgeniy Polyakov 	return err;
20481f6075eSEvgeniy Polyakov }
2051f4ec2d7SDavid Fries 
20681f6075eSEvgeniy Polyakov static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
20781f6075eSEvgeniy Polyakov {
20881f6075eSEvgeniy Polyakov 	int err;
20981f6075eSEvgeniy Polyakov 
21081f6075eSEvgeniy Polyakov 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
21181f6075eSEvgeniy Polyakov 			MODE_CMD, 0x40, value, index, NULL, 0, 1000);
21281f6075eSEvgeniy Polyakov 	if (err < 0) {
21381f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
21481f6075eSEvgeniy Polyakov 				value, index, err);
21581f6075eSEvgeniy Polyakov 		return err;
21681f6075eSEvgeniy Polyakov 	}
21781f6075eSEvgeniy Polyakov 
21881f6075eSEvgeniy Polyakov 	return err;
21981f6075eSEvgeniy Polyakov }
2201f4ec2d7SDavid Fries 
22181f6075eSEvgeniy Polyakov static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
22281f6075eSEvgeniy Polyakov {
22381f6075eSEvgeniy Polyakov 	int err;
22481f6075eSEvgeniy Polyakov 
22581f6075eSEvgeniy Polyakov 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
22681f6075eSEvgeniy Polyakov 			COMM_CMD, 0x40, value, index, NULL, 0, 1000);
22781f6075eSEvgeniy Polyakov 	if (err < 0) {
22881f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
22981f6075eSEvgeniy Polyakov 				value, index, err);
23081f6075eSEvgeniy Polyakov 		return err;
23181f6075eSEvgeniy Polyakov 	}
23281f6075eSEvgeniy Polyakov 
23381f6075eSEvgeniy Polyakov 	return err;
23481f6075eSEvgeniy Polyakov }
23581f6075eSEvgeniy Polyakov 
23681f6075eSEvgeniy Polyakov static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
23781f6075eSEvgeniy Polyakov 				 unsigned char *buf, int size)
23881f6075eSEvgeniy Polyakov {
23981f6075eSEvgeniy Polyakov 	int count, err;
24081f6075eSEvgeniy Polyakov 
241e9b5a495SLi Zefan 	memset(st, 0, sizeof(*st));
24281f6075eSEvgeniy Polyakov 
24381f6075eSEvgeniy Polyakov 	count = 0;
24481f6075eSEvgeniy Polyakov 	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
24581f6075eSEvgeniy Polyakov 	if (err < 0) {
24681f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
24781f6075eSEvgeniy Polyakov 		return err;
24881f6075eSEvgeniy Polyakov 	}
24981f6075eSEvgeniy Polyakov 
25081f6075eSEvgeniy Polyakov 	if (count >= sizeof(*st))
25181f6075eSEvgeniy Polyakov 		memcpy(st, buf, sizeof(*st));
25281f6075eSEvgeniy Polyakov 
25381f6075eSEvgeniy Polyakov 	return count;
25481f6075eSEvgeniy Polyakov }
25581f6075eSEvgeniy Polyakov 
2564b9cf1bcSDavid Fries static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
25781f6075eSEvgeniy Polyakov {
2584b9cf1bcSDavid Fries 	printk(KERN_INFO "%45s: %8x\n", str, buf[off]);
2594b9cf1bcSDavid Fries }
26081f6075eSEvgeniy Polyakov 
2614b9cf1bcSDavid Fries static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
2624b9cf1bcSDavid Fries {
2634b9cf1bcSDavid Fries 	int i;
26481f6075eSEvgeniy Polyakov 
2654b9cf1bcSDavid Fries 	printk(KERN_INFO "0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
26681f6075eSEvgeniy Polyakov 	for (i=0; i<count; ++i)
26781f6075eSEvgeniy Polyakov 		printk("%02x ", buf[i]);
2684b9cf1bcSDavid Fries 	printk(KERN_INFO "\n");
26981f6075eSEvgeniy Polyakov 
27081f6075eSEvgeniy Polyakov 	if (count >= 16) {
2714b9cf1bcSDavid Fries 		ds_print_msg(buf, "enable flag", 0);
2724b9cf1bcSDavid Fries 		ds_print_msg(buf, "1-wire speed", 1);
2734b9cf1bcSDavid Fries 		ds_print_msg(buf, "strong pullup duration", 2);
2744b9cf1bcSDavid Fries 		ds_print_msg(buf, "programming pulse duration", 3);
2754b9cf1bcSDavid Fries 		ds_print_msg(buf, "pulldown slew rate control", 4);
2764b9cf1bcSDavid Fries 		ds_print_msg(buf, "write-1 low time", 5);
2774b9cf1bcSDavid Fries 		ds_print_msg(buf, "data sample offset/write-0 recovery time",
2784b9cf1bcSDavid Fries 			6);
2794b9cf1bcSDavid Fries 		ds_print_msg(buf, "reserved (test register)", 7);
2804b9cf1bcSDavid Fries 		ds_print_msg(buf, "device status flags", 8);
2814b9cf1bcSDavid Fries 		ds_print_msg(buf, "communication command byte 1", 9);
2824b9cf1bcSDavid Fries 		ds_print_msg(buf, "communication command byte 2", 10);
2834b9cf1bcSDavid Fries 		ds_print_msg(buf, "communication command buffer status", 11);
2844b9cf1bcSDavid Fries 		ds_print_msg(buf, "1-wire data output buffer status", 12);
2854b9cf1bcSDavid Fries 		ds_print_msg(buf, "1-wire data input buffer status", 13);
2864b9cf1bcSDavid Fries 		ds_print_msg(buf, "reserved", 14);
2874b9cf1bcSDavid Fries 		ds_print_msg(buf, "reserved", 15);
28881f6075eSEvgeniy Polyakov 	}
2894b9cf1bcSDavid Fries 	for (i = 16; i < count; ++i) {
2904b9cf1bcSDavid Fries 		if (buf[i] == RR_DETECT) {
2914b9cf1bcSDavid Fries 			ds_print_msg(buf, "new device detect", i);
2924b9cf1bcSDavid Fries 			continue;
29381f6075eSEvgeniy Polyakov 		}
2944b9cf1bcSDavid Fries 		ds_print_msg(buf, "Result Register Value: ", i);
2954b9cf1bcSDavid Fries 		if (buf[i] & RR_NRS)
2964b9cf1bcSDavid Fries 			printk(KERN_INFO "NRS: Reset no presence or ...\n");
2974b9cf1bcSDavid Fries 		if (buf[i] & RR_SH)
2984b9cf1bcSDavid Fries 			printk(KERN_INFO "SH: short on reset or set path\n");
2994b9cf1bcSDavid Fries 		if (buf[i] & RR_APP)
3004b9cf1bcSDavid Fries 			printk(KERN_INFO "APP: alarming presence on reset\n");
3014b9cf1bcSDavid Fries 		if (buf[i] & RR_VPP)
3024b9cf1bcSDavid Fries 			printk(KERN_INFO "VPP: 12V expected not seen\n");
3034b9cf1bcSDavid Fries 		if (buf[i] & RR_CMP)
3044b9cf1bcSDavid Fries 			printk(KERN_INFO "CMP: compare error\n");
3054b9cf1bcSDavid Fries 		if (buf[i] & RR_CRC)
3064b9cf1bcSDavid Fries 			printk(KERN_INFO "CRC: CRC error detected\n");
3074b9cf1bcSDavid Fries 		if (buf[i] & RR_RDP)
3084b9cf1bcSDavid Fries 			printk(KERN_INFO "RDP: redirected page\n");
3094b9cf1bcSDavid Fries 		if (buf[i] & RR_EOS)
3104b9cf1bcSDavid Fries 			printk(KERN_INFO "EOS: end of search error\n");
3114b9cf1bcSDavid Fries 	}
31281f6075eSEvgeniy Polyakov }
31381f6075eSEvgeniy Polyakov 
31481f6075eSEvgeniy Polyakov static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
31581f6075eSEvgeniy Polyakov {
31681f6075eSEvgeniy Polyakov 	int count, err;
31781f6075eSEvgeniy Polyakov 	struct ds_status st;
31881f6075eSEvgeniy Polyakov 
319*e464af24SDavid Fries 	/* Careful on size.  If size is less than what is available in
320*e464af24SDavid Fries 	 * the input buffer, the device fails the bulk transfer and
321*e464af24SDavid Fries 	 * clears the input buffer.  It could read the maximum size of
322*e464af24SDavid Fries 	 * the data buffer, but then do you return the first, last, or
323*e464af24SDavid Fries 	 * some set of the middle size bytes?  As long as the rest of
324*e464af24SDavid Fries 	 * the code is correct there will be size bytes waiting.  A
325*e464af24SDavid Fries 	 * call to ds_wait_status will wait until the device is idle
326*e464af24SDavid Fries 	 * and any data to be received would have been available.
327*e464af24SDavid Fries 	 */
32881f6075eSEvgeniy Polyakov 	count = 0;
32981f6075eSEvgeniy Polyakov 	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
33081f6075eSEvgeniy Polyakov 				buf, size, &count, 1000);
33181f6075eSEvgeniy Polyakov 	if (err < 0) {
3324b9cf1bcSDavid Fries 		u8 buf[0x20];
3334b9cf1bcSDavid Fries 		int count;
3344b9cf1bcSDavid Fries 
33581f6075eSEvgeniy Polyakov 		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
33681f6075eSEvgeniy Polyakov 		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
3374b9cf1bcSDavid Fries 
3384b9cf1bcSDavid Fries 		count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
3394b9cf1bcSDavid Fries 		ds_dump_status(dev, buf, count);
34081f6075eSEvgeniy Polyakov 		return err;
34181f6075eSEvgeniy Polyakov 	}
34281f6075eSEvgeniy Polyakov 
34381f6075eSEvgeniy Polyakov #if 0
34481f6075eSEvgeniy Polyakov 	{
34581f6075eSEvgeniy Polyakov 		int i;
34681f6075eSEvgeniy Polyakov 
34781f6075eSEvgeniy Polyakov 		printk("%s: count=%d: ", __func__, count);
34881f6075eSEvgeniy Polyakov 		for (i=0; i<count; ++i)
34981f6075eSEvgeniy Polyakov 			printk("%02x ", buf[i]);
35081f6075eSEvgeniy Polyakov 		printk("\n");
35181f6075eSEvgeniy Polyakov 	}
35281f6075eSEvgeniy Polyakov #endif
35381f6075eSEvgeniy Polyakov 	return count;
35481f6075eSEvgeniy Polyakov }
35581f6075eSEvgeniy Polyakov 
35681f6075eSEvgeniy Polyakov static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
35781f6075eSEvgeniy Polyakov {
35881f6075eSEvgeniy Polyakov 	int count, err;
35981f6075eSEvgeniy Polyakov 
36081f6075eSEvgeniy Polyakov 	count = 0;
36181f6075eSEvgeniy Polyakov 	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
36281f6075eSEvgeniy Polyakov 	if (err < 0) {
36395cfaebfSDavid Fries 		printk(KERN_ERR "Failed to write 1-wire data to ep0x%x: "
36495cfaebfSDavid Fries 			"err=%d.\n", dev->ep[EP_DATA_OUT], err);
36581f6075eSEvgeniy Polyakov 		return err;
36681f6075eSEvgeniy Polyakov 	}
36781f6075eSEvgeniy Polyakov 
36881f6075eSEvgeniy Polyakov 	return err;
36981f6075eSEvgeniy Polyakov }
37081f6075eSEvgeniy Polyakov 
37181f6075eSEvgeniy Polyakov #if 0
37281f6075eSEvgeniy Polyakov 
37381f6075eSEvgeniy Polyakov int ds_stop_pulse(struct ds_device *dev, int limit)
37481f6075eSEvgeniy Polyakov {
37581f6075eSEvgeniy Polyakov 	struct ds_status st;
37681f6075eSEvgeniy Polyakov 	int count = 0, err = 0;
37781f6075eSEvgeniy Polyakov 	u8 buf[0x20];
37881f6075eSEvgeniy Polyakov 
37981f6075eSEvgeniy Polyakov 	do {
38081f6075eSEvgeniy Polyakov 		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
38181f6075eSEvgeniy Polyakov 		if (err)
38281f6075eSEvgeniy Polyakov 			break;
38381f6075eSEvgeniy Polyakov 		err = ds_send_control(dev, CTL_RESUME_EXE, 0);
38481f6075eSEvgeniy Polyakov 		if (err)
38581f6075eSEvgeniy Polyakov 			break;
38681f6075eSEvgeniy Polyakov 		err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
38781f6075eSEvgeniy Polyakov 		if (err)
38881f6075eSEvgeniy Polyakov 			break;
38981f6075eSEvgeniy Polyakov 
39081f6075eSEvgeniy Polyakov 		if ((st.status & ST_SPUA) == 0) {
39181f6075eSEvgeniy Polyakov 			err = ds_send_control_mode(dev, MOD_PULSE_EN, 0);
39281f6075eSEvgeniy Polyakov 			if (err)
39381f6075eSEvgeniy Polyakov 				break;
39481f6075eSEvgeniy Polyakov 		}
39581f6075eSEvgeniy Polyakov 	} while(++count < limit);
39681f6075eSEvgeniy Polyakov 
39781f6075eSEvgeniy Polyakov 	return err;
39881f6075eSEvgeniy Polyakov }
39981f6075eSEvgeniy Polyakov 
40081f6075eSEvgeniy Polyakov int ds_detect(struct ds_device *dev, struct ds_status *st)
40181f6075eSEvgeniy Polyakov {
40281f6075eSEvgeniy Polyakov 	int err;
40381f6075eSEvgeniy Polyakov 
40481f6075eSEvgeniy Polyakov 	err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
40581f6075eSEvgeniy Polyakov 	if (err)
40681f6075eSEvgeniy Polyakov 		return err;
40781f6075eSEvgeniy Polyakov 
40881f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
40981f6075eSEvgeniy Polyakov 	if (err)
41081f6075eSEvgeniy Polyakov 		return err;
41181f6075eSEvgeniy Polyakov 
41281f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
41381f6075eSEvgeniy Polyakov 	if (err)
41481f6075eSEvgeniy Polyakov 		return err;
41581f6075eSEvgeniy Polyakov 
41681f6075eSEvgeniy Polyakov 	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
41781f6075eSEvgeniy Polyakov 	if (err)
41881f6075eSEvgeniy Polyakov 		return err;
41981f6075eSEvgeniy Polyakov 
4204b9cf1bcSDavid Fries 	err = ds_dump_status(dev, st);
42181f6075eSEvgeniy Polyakov 
42281f6075eSEvgeniy Polyakov 	return err;
42381f6075eSEvgeniy Polyakov }
42481f6075eSEvgeniy Polyakov 
42581f6075eSEvgeniy Polyakov #endif  /*  0  */
42681f6075eSEvgeniy Polyakov 
42781f6075eSEvgeniy Polyakov static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
42881f6075eSEvgeniy Polyakov {
42981f6075eSEvgeniy Polyakov 	u8 buf[0x20];
43081f6075eSEvgeniy Polyakov 	int err, count = 0;
43181f6075eSEvgeniy Polyakov 
43281f6075eSEvgeniy Polyakov 	do {
43381f6075eSEvgeniy Polyakov 		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
43481f6075eSEvgeniy Polyakov #if 0
43581f6075eSEvgeniy Polyakov 		if (err >= 0) {
43681f6075eSEvgeniy Polyakov 			int i;
43781f6075eSEvgeniy Polyakov 			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
43881f6075eSEvgeniy Polyakov 			for (i=0; i<err; ++i)
43981f6075eSEvgeniy Polyakov 				printk("%02x ", buf[i]);
44081f6075eSEvgeniy Polyakov 			printk("\n");
44181f6075eSEvgeniy Polyakov 		}
44281f6075eSEvgeniy Polyakov #endif
44381f6075eSEvgeniy Polyakov 	} while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
44481f6075eSEvgeniy Polyakov 
4454b9cf1bcSDavid Fries 	if (err >= 16 && st->status & ST_EPOF) {
4464b9cf1bcSDavid Fries 		printk(KERN_INFO "Resetting device after ST_EPOF.\n");
4474b9cf1bcSDavid Fries 		ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
4484b9cf1bcSDavid Fries 		/* Always dump the device status. */
4494b9cf1bcSDavid Fries 		count = 101;
4504b9cf1bcSDavid Fries 	}
45181f6075eSEvgeniy Polyakov 
4524b9cf1bcSDavid Fries 	/* Dump the status for errors or if there is extended return data.
4534b9cf1bcSDavid Fries 	 * The extended status includes new device detection (maybe someone
4544b9cf1bcSDavid Fries 	 * can do something with it).
4554b9cf1bcSDavid Fries 	 */
4564b9cf1bcSDavid Fries 	if (err > 16 || count >= 100 || err < 0)
4574b9cf1bcSDavid Fries 		ds_dump_status(dev, buf, err);
4584b9cf1bcSDavid Fries 
4594b9cf1bcSDavid Fries 	/* Extended data isn't an error.  Well, a short is, but the dump
4604b9cf1bcSDavid Fries 	 * would have already told the user that and we can't do anything
4614b9cf1bcSDavid Fries 	 * about it in software anyway.
4624b9cf1bcSDavid Fries 	 */
4634b9cf1bcSDavid Fries 	if (count >= 100 || err < 0)
46481f6075eSEvgeniy Polyakov 		return -1;
4654b9cf1bcSDavid Fries 	else
46681f6075eSEvgeniy Polyakov 		return 0;
46781f6075eSEvgeniy Polyakov }
46881f6075eSEvgeniy Polyakov 
4697a4b9706SDavid Fries static int ds_reset(struct ds_device *dev)
47081f6075eSEvgeniy Polyakov {
47181f6075eSEvgeniy Polyakov 	int err;
47281f6075eSEvgeniy Polyakov 
47381f6075eSEvgeniy Polyakov 	//err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
47481f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, 0x43, SPEED_NORMAL);
47581f6075eSEvgeniy Polyakov 	if (err)
47681f6075eSEvgeniy Polyakov 		return err;
47781f6075eSEvgeniy Polyakov 
47881f6075eSEvgeniy Polyakov 	return 0;
47981f6075eSEvgeniy Polyakov }
48081f6075eSEvgeniy Polyakov 
48181f6075eSEvgeniy Polyakov #if 0
48281f6075eSEvgeniy Polyakov static int ds_set_speed(struct ds_device *dev, int speed)
48381f6075eSEvgeniy Polyakov {
48481f6075eSEvgeniy Polyakov 	int err;
48581f6075eSEvgeniy Polyakov 
48681f6075eSEvgeniy Polyakov 	if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
48781f6075eSEvgeniy Polyakov 		return -EINVAL;
48881f6075eSEvgeniy Polyakov 
48981f6075eSEvgeniy Polyakov 	if (speed != SPEED_OVERDRIVE)
49081f6075eSEvgeniy Polyakov 		speed = SPEED_FLEXIBLE;
49181f6075eSEvgeniy Polyakov 
49281f6075eSEvgeniy Polyakov 	speed &= 0xff;
49381f6075eSEvgeniy Polyakov 
49481f6075eSEvgeniy Polyakov 	err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
49581f6075eSEvgeniy Polyakov 	if (err)
49681f6075eSEvgeniy Polyakov 		return err;
49781f6075eSEvgeniy Polyakov 
49881f6075eSEvgeniy Polyakov 	return err;
49981f6075eSEvgeniy Polyakov }
50081f6075eSEvgeniy Polyakov #endif  /*  0  */
50181f6075eSEvgeniy Polyakov 
5021f4ec2d7SDavid Fries static int ds_set_pullup(struct ds_device *dev, int delay)
50381f6075eSEvgeniy Polyakov {
50481f6075eSEvgeniy Polyakov 	int err;
50581f6075eSEvgeniy Polyakov 	u8 del = 1 + (u8)(delay >> 4);
50681f6075eSEvgeniy Polyakov 
5071f4ec2d7SDavid Fries 	dev->spu_sleep = 0;
5081f4ec2d7SDavid Fries 	err = ds_send_control_mode(dev, MOD_PULSE_EN, delay ? PULSE_SPUE : 0);
50981f6075eSEvgeniy Polyakov 	if (err)
51081f6075eSEvgeniy Polyakov 		return err;
51181f6075eSEvgeniy Polyakov 
5121f4ec2d7SDavid Fries 	if (delay) {
51381f6075eSEvgeniy Polyakov 		err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
51481f6075eSEvgeniy Polyakov 		if (err)
51581f6075eSEvgeniy Polyakov 			return err;
51681f6075eSEvgeniy Polyakov 
5171f4ec2d7SDavid Fries 		/* Just storing delay would not get the trunication and
5181f4ec2d7SDavid Fries 		 * roundup.
5191f4ec2d7SDavid Fries 		 */
5201f4ec2d7SDavid Fries 		dev->spu_sleep = del<<4;
5211f4ec2d7SDavid Fries 	}
52281f6075eSEvgeniy Polyakov 
52381f6075eSEvgeniy Polyakov 	return err;
52481f6075eSEvgeniy Polyakov }
52581f6075eSEvgeniy Polyakov 
52681f6075eSEvgeniy Polyakov static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
52781f6075eSEvgeniy Polyakov {
5286e10f654SDavid Fries 	int err;
52981f6075eSEvgeniy Polyakov 	struct ds_status st;
53081f6075eSEvgeniy Polyakov 
5316e10f654SDavid Fries 	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit ? COMM_D : 0),
5326e10f654SDavid Fries 		0);
53381f6075eSEvgeniy Polyakov 	if (err)
53481f6075eSEvgeniy Polyakov 		return err;
53581f6075eSEvgeniy Polyakov 
5366e10f654SDavid Fries 	ds_wait_status(dev, &st);
53781f6075eSEvgeniy Polyakov 
53881f6075eSEvgeniy Polyakov 	err = ds_recv_data(dev, tbit, sizeof(*tbit));
53981f6075eSEvgeniy Polyakov 	if (err < 0)
54081f6075eSEvgeniy Polyakov 		return err;
54181f6075eSEvgeniy Polyakov 
54281f6075eSEvgeniy Polyakov 	return 0;
54381f6075eSEvgeniy Polyakov }
54481f6075eSEvgeniy Polyakov 
545a08e2d33SDavid Fries #if 0
54681f6075eSEvgeniy Polyakov static int ds_write_bit(struct ds_device *dev, u8 bit)
54781f6075eSEvgeniy Polyakov {
54881f6075eSEvgeniy Polyakov 	int err;
54981f6075eSEvgeniy Polyakov 	struct ds_status st;
55081f6075eSEvgeniy Polyakov 
551e1c86d22SDavid Fries 	/* Set COMM_ICP to write without a readback.  Note, this will
552e1c86d22SDavid Fries 	 * produce one time slot, a down followed by an up with COMM_D
553e1c86d22SDavid Fries 	 * only determing the timing.
554e1c86d22SDavid Fries 	 */
555e1c86d22SDavid Fries 	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
556e1c86d22SDavid Fries 		(bit ? COMM_D : 0), 0);
55781f6075eSEvgeniy Polyakov 	if (err)
55881f6075eSEvgeniy Polyakov 		return err;
55981f6075eSEvgeniy Polyakov 
56081f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
56181f6075eSEvgeniy Polyakov 
56281f6075eSEvgeniy Polyakov 	return 0;
56381f6075eSEvgeniy Polyakov }
564a08e2d33SDavid Fries #endif
56581f6075eSEvgeniy Polyakov 
56681f6075eSEvgeniy Polyakov static int ds_write_byte(struct ds_device *dev, u8 byte)
56781f6075eSEvgeniy Polyakov {
56881f6075eSEvgeniy Polyakov 	int err;
56981f6075eSEvgeniy Polyakov 	struct ds_status st;
57081f6075eSEvgeniy Polyakov 	u8 rbyte;
57181f6075eSEvgeniy Polyakov 
57281f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
57381f6075eSEvgeniy Polyakov 	if (err)
57481f6075eSEvgeniy Polyakov 		return err;
57581f6075eSEvgeniy Polyakov 
5761f4ec2d7SDavid Fries 	if (dev->spu_sleep)
5771f4ec2d7SDavid Fries 		msleep(dev->spu_sleep);
5781f4ec2d7SDavid Fries 
57981f6075eSEvgeniy Polyakov 	err = ds_wait_status(dev, &st);
58081f6075eSEvgeniy Polyakov 	if (err)
58181f6075eSEvgeniy Polyakov 		return err;
58281f6075eSEvgeniy Polyakov 
58381f6075eSEvgeniy Polyakov 	err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
58481f6075eSEvgeniy Polyakov 	if (err < 0)
58581f6075eSEvgeniy Polyakov 		return err;
58681f6075eSEvgeniy Polyakov 
58781f6075eSEvgeniy Polyakov 	return !(byte == rbyte);
58881f6075eSEvgeniy Polyakov }
58981f6075eSEvgeniy Polyakov 
59081f6075eSEvgeniy Polyakov static int ds_read_byte(struct ds_device *dev, u8 *byte)
59181f6075eSEvgeniy Polyakov {
59281f6075eSEvgeniy Polyakov 	int err;
59381f6075eSEvgeniy Polyakov 	struct ds_status st;
59481f6075eSEvgeniy Polyakov 
59581f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff);
59681f6075eSEvgeniy Polyakov 	if (err)
59781f6075eSEvgeniy Polyakov 		return err;
59881f6075eSEvgeniy Polyakov 
59981f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
60081f6075eSEvgeniy Polyakov 
60181f6075eSEvgeniy Polyakov 	err = ds_recv_data(dev, byte, sizeof(*byte));
60281f6075eSEvgeniy Polyakov 	if (err < 0)
60381f6075eSEvgeniy Polyakov 		return err;
60481f6075eSEvgeniy Polyakov 
60581f6075eSEvgeniy Polyakov 	return 0;
60681f6075eSEvgeniy Polyakov }
60781f6075eSEvgeniy Polyakov 
60881f6075eSEvgeniy Polyakov static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
60981f6075eSEvgeniy Polyakov {
61081f6075eSEvgeniy Polyakov 	struct ds_status st;
61181f6075eSEvgeniy Polyakov 	int err;
61281f6075eSEvgeniy Polyakov 
61381f6075eSEvgeniy Polyakov 	if (len > 64*1024)
61481f6075eSEvgeniy Polyakov 		return -E2BIG;
61581f6075eSEvgeniy Polyakov 
61681f6075eSEvgeniy Polyakov 	memset(buf, 0xFF, len);
61781f6075eSEvgeniy Polyakov 
61881f6075eSEvgeniy Polyakov 	err = ds_send_data(dev, buf, len);
61981f6075eSEvgeniy Polyakov 	if (err < 0)
62081f6075eSEvgeniy Polyakov 		return err;
62181f6075eSEvgeniy Polyakov 
6221f4ec2d7SDavid Fries 	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM, len);
62381f6075eSEvgeniy Polyakov 	if (err)
62481f6075eSEvgeniy Polyakov 		return err;
62581f6075eSEvgeniy Polyakov 
62681f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
62781f6075eSEvgeniy Polyakov 
62881f6075eSEvgeniy Polyakov 	memset(buf, 0x00, len);
62981f6075eSEvgeniy Polyakov 	err = ds_recv_data(dev, buf, len);
63081f6075eSEvgeniy Polyakov 
63181f6075eSEvgeniy Polyakov 	return err;
63281f6075eSEvgeniy Polyakov }
63381f6075eSEvgeniy Polyakov 
63481f6075eSEvgeniy Polyakov static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
63581f6075eSEvgeniy Polyakov {
63681f6075eSEvgeniy Polyakov 	int err;
63781f6075eSEvgeniy Polyakov 	struct ds_status st;
63881f6075eSEvgeniy Polyakov 
63981f6075eSEvgeniy Polyakov 	err = ds_send_data(dev, buf, len);
64081f6075eSEvgeniy Polyakov 	if (err < 0)
64181f6075eSEvgeniy Polyakov 		return err;
64281f6075eSEvgeniy Polyakov 
64381f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
64481f6075eSEvgeniy Polyakov 
64581f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
64681f6075eSEvgeniy Polyakov 	if (err)
64781f6075eSEvgeniy Polyakov 		return err;
64881f6075eSEvgeniy Polyakov 
6491f4ec2d7SDavid Fries 	if (dev->spu_sleep)
6501f4ec2d7SDavid Fries 		msleep(dev->spu_sleep);
6511f4ec2d7SDavid Fries 
65281f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
65381f6075eSEvgeniy Polyakov 
65481f6075eSEvgeniy Polyakov 	err = ds_recv_data(dev, buf, len);
65581f6075eSEvgeniy Polyakov 	if (err < 0)
65681f6075eSEvgeniy Polyakov 		return err;
65781f6075eSEvgeniy Polyakov 
65881f6075eSEvgeniy Polyakov 	return !(err == len);
65981f6075eSEvgeniy Polyakov }
66081f6075eSEvgeniy Polyakov 
66181f6075eSEvgeniy Polyakov #if 0
66281f6075eSEvgeniy Polyakov 
66381f6075eSEvgeniy Polyakov static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
66481f6075eSEvgeniy Polyakov {
66581f6075eSEvgeniy Polyakov 	int err;
66681f6075eSEvgeniy Polyakov 	u16 value, index;
66781f6075eSEvgeniy Polyakov 	struct ds_status st;
66881f6075eSEvgeniy Polyakov 
66981f6075eSEvgeniy Polyakov 	memset(buf, 0, sizeof(buf));
67081f6075eSEvgeniy Polyakov 
67181f6075eSEvgeniy Polyakov 	err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
67281f6075eSEvgeniy Polyakov 	if (err)
67381f6075eSEvgeniy Polyakov 		return err;
67481f6075eSEvgeniy Polyakov 
67581f6075eSEvgeniy Polyakov 	ds_wait_status(ds_dev, &st);
67681f6075eSEvgeniy Polyakov 
67781f6075eSEvgeniy Polyakov 	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
67881f6075eSEvgeniy Polyakov 	index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
67981f6075eSEvgeniy Polyakov 	err = ds_send_control(ds_dev, value, index);
68081f6075eSEvgeniy Polyakov 	if (err)
68181f6075eSEvgeniy Polyakov 		return err;
68281f6075eSEvgeniy Polyakov 
68381f6075eSEvgeniy Polyakov 	ds_wait_status(ds_dev, &st);
68481f6075eSEvgeniy Polyakov 
68581f6075eSEvgeniy Polyakov 	err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
68681f6075eSEvgeniy Polyakov 	if (err < 0)
68781f6075eSEvgeniy Polyakov 		return err;
68881f6075eSEvgeniy Polyakov 
68981f6075eSEvgeniy Polyakov 	return err/8;
69081f6075eSEvgeniy Polyakov }
69181f6075eSEvgeniy Polyakov 
69281f6075eSEvgeniy Polyakov static int ds_match_access(struct ds_device *dev, u64 init)
69381f6075eSEvgeniy Polyakov {
69481f6075eSEvgeniy Polyakov 	int err;
69581f6075eSEvgeniy Polyakov 	struct ds_status st;
69681f6075eSEvgeniy Polyakov 
69781f6075eSEvgeniy Polyakov 	err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
69881f6075eSEvgeniy Polyakov 	if (err)
69981f6075eSEvgeniy Polyakov 		return err;
70081f6075eSEvgeniy Polyakov 
70181f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
70281f6075eSEvgeniy Polyakov 
70381f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
70481f6075eSEvgeniy Polyakov 	if (err)
70581f6075eSEvgeniy Polyakov 		return err;
70681f6075eSEvgeniy Polyakov 
70781f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
70881f6075eSEvgeniy Polyakov 
70981f6075eSEvgeniy Polyakov 	return 0;
71081f6075eSEvgeniy Polyakov }
71181f6075eSEvgeniy Polyakov 
71281f6075eSEvgeniy Polyakov static int ds_set_path(struct ds_device *dev, u64 init)
71381f6075eSEvgeniy Polyakov {
71481f6075eSEvgeniy Polyakov 	int err;
71581f6075eSEvgeniy Polyakov 	struct ds_status st;
71681f6075eSEvgeniy Polyakov 	u8 buf[9];
71781f6075eSEvgeniy Polyakov 
71881f6075eSEvgeniy Polyakov 	memcpy(buf, &init, 8);
71981f6075eSEvgeniy Polyakov 	buf[8] = BRANCH_MAIN;
72081f6075eSEvgeniy Polyakov 
72181f6075eSEvgeniy Polyakov 	err = ds_send_data(dev, buf, sizeof(buf));
72281f6075eSEvgeniy Polyakov 	if (err)
72381f6075eSEvgeniy Polyakov 		return err;
72481f6075eSEvgeniy Polyakov 
72581f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
72681f6075eSEvgeniy Polyakov 
72781f6075eSEvgeniy Polyakov 	err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
72881f6075eSEvgeniy Polyakov 	if (err)
72981f6075eSEvgeniy Polyakov 		return err;
73081f6075eSEvgeniy Polyakov 
73181f6075eSEvgeniy Polyakov 	ds_wait_status(dev, &st);
73281f6075eSEvgeniy Polyakov 
73381f6075eSEvgeniy Polyakov 	return 0;
73481f6075eSEvgeniy Polyakov }
73581f6075eSEvgeniy Polyakov 
73681f6075eSEvgeniy Polyakov #endif  /*  0  */
73781f6075eSEvgeniy Polyakov 
73881f6075eSEvgeniy Polyakov static u8 ds9490r_touch_bit(void *data, u8 bit)
73981f6075eSEvgeniy Polyakov {
74081f6075eSEvgeniy Polyakov 	u8 ret;
74181f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
74281f6075eSEvgeniy Polyakov 
74381f6075eSEvgeniy Polyakov 	if (ds_touch_bit(dev, bit, &ret))
74481f6075eSEvgeniy Polyakov 		return 0;
74581f6075eSEvgeniy Polyakov 
74681f6075eSEvgeniy Polyakov 	return ret;
74781f6075eSEvgeniy Polyakov }
74881f6075eSEvgeniy Polyakov 
749a08e2d33SDavid Fries #if 0
75081f6075eSEvgeniy Polyakov static void ds9490r_write_bit(void *data, u8 bit)
75181f6075eSEvgeniy Polyakov {
75281f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
75381f6075eSEvgeniy Polyakov 
75481f6075eSEvgeniy Polyakov 	ds_write_bit(dev, bit);
75581f6075eSEvgeniy Polyakov }
75681f6075eSEvgeniy Polyakov 
75781f6075eSEvgeniy Polyakov static u8 ds9490r_read_bit(void *data)
75881f6075eSEvgeniy Polyakov {
75981f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
76081f6075eSEvgeniy Polyakov 	int err;
76181f6075eSEvgeniy Polyakov 	u8 bit = 0;
76281f6075eSEvgeniy Polyakov 
76381f6075eSEvgeniy Polyakov 	err = ds_touch_bit(dev, 1, &bit);
76481f6075eSEvgeniy Polyakov 	if (err)
76581f6075eSEvgeniy Polyakov 		return 0;
76681f6075eSEvgeniy Polyakov 
76781f6075eSEvgeniy Polyakov 	return bit & 1;
76881f6075eSEvgeniy Polyakov }
769a08e2d33SDavid Fries #endif
770a08e2d33SDavid Fries 
771a08e2d33SDavid Fries static void ds9490r_write_byte(void *data, u8 byte)
772a08e2d33SDavid Fries {
773a08e2d33SDavid Fries 	struct ds_device *dev = data;
774a08e2d33SDavid Fries 
775a08e2d33SDavid Fries 	ds_write_byte(dev, byte);
776a08e2d33SDavid Fries }
77781f6075eSEvgeniy Polyakov 
77881f6075eSEvgeniy Polyakov static u8 ds9490r_read_byte(void *data)
77981f6075eSEvgeniy Polyakov {
78081f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
78181f6075eSEvgeniy Polyakov 	int err;
78281f6075eSEvgeniy Polyakov 	u8 byte = 0;
78381f6075eSEvgeniy Polyakov 
78481f6075eSEvgeniy Polyakov 	err = ds_read_byte(dev, &byte);
78581f6075eSEvgeniy Polyakov 	if (err)
78681f6075eSEvgeniy Polyakov 		return 0;
78781f6075eSEvgeniy Polyakov 
78881f6075eSEvgeniy Polyakov 	return byte;
78981f6075eSEvgeniy Polyakov }
79081f6075eSEvgeniy Polyakov 
79181f6075eSEvgeniy Polyakov static void ds9490r_write_block(void *data, const u8 *buf, int len)
79281f6075eSEvgeniy Polyakov {
79381f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
79481f6075eSEvgeniy Polyakov 
79581f6075eSEvgeniy Polyakov 	ds_write_block(dev, (u8 *)buf, len);
79681f6075eSEvgeniy Polyakov }
79781f6075eSEvgeniy Polyakov 
79881f6075eSEvgeniy Polyakov static u8 ds9490r_read_block(void *data, u8 *buf, int len)
79981f6075eSEvgeniy Polyakov {
80081f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
80181f6075eSEvgeniy Polyakov 	int err;
80281f6075eSEvgeniy Polyakov 
80381f6075eSEvgeniy Polyakov 	err = ds_read_block(dev, buf, len);
80481f6075eSEvgeniy Polyakov 	if (err < 0)
80581f6075eSEvgeniy Polyakov 		return 0;
80681f6075eSEvgeniy Polyakov 
80781f6075eSEvgeniy Polyakov 	return len;
80881f6075eSEvgeniy Polyakov }
80981f6075eSEvgeniy Polyakov 
81081f6075eSEvgeniy Polyakov static u8 ds9490r_reset(void *data)
81181f6075eSEvgeniy Polyakov {
81281f6075eSEvgeniy Polyakov 	struct ds_device *dev = data;
81381f6075eSEvgeniy Polyakov 	int err;
81481f6075eSEvgeniy Polyakov 
8157a4b9706SDavid Fries 	err = ds_reset(dev);
81681f6075eSEvgeniy Polyakov 	if (err)
81781f6075eSEvgeniy Polyakov 		return 1;
81881f6075eSEvgeniy Polyakov 
81981f6075eSEvgeniy Polyakov 	return 0;
82081f6075eSEvgeniy Polyakov }
82181f6075eSEvgeniy Polyakov 
8221f4ec2d7SDavid Fries static u8 ds9490r_set_pullup(void *data, int delay)
8231f4ec2d7SDavid Fries {
8241f4ec2d7SDavid Fries 	struct ds_device *dev = data;
8251f4ec2d7SDavid Fries 
8261f4ec2d7SDavid Fries 	if (ds_set_pullup(dev, delay))
8271f4ec2d7SDavid Fries 		return 1;
8281f4ec2d7SDavid Fries 
8291f4ec2d7SDavid Fries 	return 0;
8301f4ec2d7SDavid Fries }
8311f4ec2d7SDavid Fries 
83281f6075eSEvgeniy Polyakov static int ds_w1_init(struct ds_device *dev)
83381f6075eSEvgeniy Polyakov {
83481f6075eSEvgeniy Polyakov 	memset(&dev->master, 0, sizeof(struct w1_bus_master));
83581f6075eSEvgeniy Polyakov 
836*e464af24SDavid Fries 	/* Reset the device as it can be in a bad state.
837*e464af24SDavid Fries 	 * This is necessary because a block write will wait for data
838*e464af24SDavid Fries 	 * to be placed in the output buffer and block any later
839*e464af24SDavid Fries 	 * commands which will keep accumulating and the device will
840*e464af24SDavid Fries 	 * not be idle.  Another case is removing the ds2490 module
841*e464af24SDavid Fries 	 * while a bus search is in progress, somehow a few commands
842*e464af24SDavid Fries 	 * get through, but the input transfers fail leaving data in
843*e464af24SDavid Fries 	 * the input buffer.  This will cause the next read to fail
844*e464af24SDavid Fries 	 * see the note in ds_recv_data.
845*e464af24SDavid Fries 	 */
846*e464af24SDavid Fries 	ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
847*e464af24SDavid Fries 
84881f6075eSEvgeniy Polyakov 	dev->master.data	= dev;
84981f6075eSEvgeniy Polyakov 	dev->master.touch_bit	= &ds9490r_touch_bit;
850a08e2d33SDavid Fries 	/* read_bit and write_bit in w1_bus_master are expected to set and
851a08e2d33SDavid Fries 	 * sample the line level.  For write_bit that means it is expected to
852a08e2d33SDavid Fries 	 * set it to that value and leave it there.  ds2490 only supports an
853a08e2d33SDavid Fries 	 * individual time slot at the lowest level.  The requirement from
854a08e2d33SDavid Fries 	 * pulling the bus state down to reading the state is 15us, something
855a08e2d33SDavid Fries 	 * that isn't realistic on the USB bus anyway.
85681f6075eSEvgeniy Polyakov 	dev->master.read_bit	= &ds9490r_read_bit;
85781f6075eSEvgeniy Polyakov 	dev->master.write_bit	= &ds9490r_write_bit;
858a08e2d33SDavid Fries 	*/
85981f6075eSEvgeniy Polyakov 	dev->master.read_byte	= &ds9490r_read_byte;
86081f6075eSEvgeniy Polyakov 	dev->master.write_byte	= &ds9490r_write_byte;
86181f6075eSEvgeniy Polyakov 	dev->master.read_block	= &ds9490r_read_block;
86281f6075eSEvgeniy Polyakov 	dev->master.write_block	= &ds9490r_write_block;
86381f6075eSEvgeniy Polyakov 	dev->master.reset_bus	= &ds9490r_reset;
8641f4ec2d7SDavid Fries 	dev->master.set_pullup	= &ds9490r_set_pullup;
86581f6075eSEvgeniy Polyakov 
86681f6075eSEvgeniy Polyakov 	return w1_add_master_device(&dev->master);
86781f6075eSEvgeniy Polyakov }
86881f6075eSEvgeniy Polyakov 
86981f6075eSEvgeniy Polyakov static void ds_w1_fini(struct ds_device *dev)
87081f6075eSEvgeniy Polyakov {
87181f6075eSEvgeniy Polyakov 	w1_remove_master_device(&dev->master);
87281f6075eSEvgeniy Polyakov }
87381f6075eSEvgeniy Polyakov 
87481f6075eSEvgeniy Polyakov static int ds_probe(struct usb_interface *intf,
87581f6075eSEvgeniy Polyakov 		    const struct usb_device_id *udev_id)
87681f6075eSEvgeniy Polyakov {
87781f6075eSEvgeniy Polyakov 	struct usb_device *udev = interface_to_usbdev(intf);
87881f6075eSEvgeniy Polyakov 	struct usb_endpoint_descriptor *endpoint;
87981f6075eSEvgeniy Polyakov 	struct usb_host_interface *iface_desc;
88081f6075eSEvgeniy Polyakov 	struct ds_device *dev;
88181f6075eSEvgeniy Polyakov 	int i, err;
88281f6075eSEvgeniy Polyakov 
88381f6075eSEvgeniy Polyakov 	dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
88481f6075eSEvgeniy Polyakov 	if (!dev) {
88581f6075eSEvgeniy Polyakov 		printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
88681f6075eSEvgeniy Polyakov 		return -ENOMEM;
88781f6075eSEvgeniy Polyakov 	}
8881f4ec2d7SDavid Fries 	dev->spu_sleep = 0;
88981f6075eSEvgeniy Polyakov 	dev->udev = usb_get_dev(udev);
89081f6075eSEvgeniy Polyakov 	if (!dev->udev) {
89181f6075eSEvgeniy Polyakov 		err = -ENOMEM;
89281f6075eSEvgeniy Polyakov 		goto err_out_free;
89381f6075eSEvgeniy Polyakov 	}
89481f6075eSEvgeniy Polyakov 	memset(dev->ep, 0, sizeof(dev->ep));
89581f6075eSEvgeniy Polyakov 
89681f6075eSEvgeniy Polyakov 	usb_set_intfdata(intf, dev);
89781f6075eSEvgeniy Polyakov 
89881f6075eSEvgeniy Polyakov 	err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
89981f6075eSEvgeniy Polyakov 	if (err) {
90081f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
90181f6075eSEvgeniy Polyakov 				intf->altsetting[0].desc.bInterfaceNumber, err);
90281f6075eSEvgeniy Polyakov 		goto err_out_clear;
90381f6075eSEvgeniy Polyakov 	}
90481f6075eSEvgeniy Polyakov 
90581f6075eSEvgeniy Polyakov 	err = usb_reset_configuration(dev->udev);
90681f6075eSEvgeniy Polyakov 	if (err) {
90781f6075eSEvgeniy Polyakov 		printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
90881f6075eSEvgeniy Polyakov 		goto err_out_clear;
90981f6075eSEvgeniy Polyakov 	}
91081f6075eSEvgeniy Polyakov 
91181f6075eSEvgeniy Polyakov 	iface_desc = &intf->altsetting[0];
91281f6075eSEvgeniy Polyakov 	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
91381f6075eSEvgeniy Polyakov 		printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
91481f6075eSEvgeniy Polyakov 		err = -EINVAL;
91581f6075eSEvgeniy Polyakov 		goto err_out_clear;
91681f6075eSEvgeniy Polyakov 	}
91781f6075eSEvgeniy Polyakov 
91881f6075eSEvgeniy Polyakov 	/*
91981f6075eSEvgeniy Polyakov 	 * This loop doesn'd show control 0 endpoint,
92081f6075eSEvgeniy Polyakov 	 * so we will fill only 1-3 endpoints entry.
92181f6075eSEvgeniy Polyakov 	 */
92281f6075eSEvgeniy Polyakov 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
92381f6075eSEvgeniy Polyakov 		endpoint = &iface_desc->endpoint[i].desc;
92481f6075eSEvgeniy Polyakov 
92581f6075eSEvgeniy Polyakov 		dev->ep[i+1] = endpoint->bEndpointAddress;
92681f6075eSEvgeniy Polyakov #if 0
92781f6075eSEvgeniy Polyakov 		printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
92881f6075eSEvgeniy Polyakov 			i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
92981f6075eSEvgeniy Polyakov 			(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
93081f6075eSEvgeniy Polyakov 			endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
93181f6075eSEvgeniy Polyakov #endif
93281f6075eSEvgeniy Polyakov 	}
93381f6075eSEvgeniy Polyakov 
93481f6075eSEvgeniy Polyakov 	err = ds_w1_init(dev);
93581f6075eSEvgeniy Polyakov 	if (err)
93681f6075eSEvgeniy Polyakov 		goto err_out_clear;
93781f6075eSEvgeniy Polyakov 
938abd52a13SEvgeniy Polyakov 	mutex_lock(&ds_mutex);
93981f6075eSEvgeniy Polyakov 	list_add_tail(&dev->ds_entry, &ds_devices);
940abd52a13SEvgeniy Polyakov 	mutex_unlock(&ds_mutex);
94181f6075eSEvgeniy Polyakov 
94281f6075eSEvgeniy Polyakov 	return 0;
94381f6075eSEvgeniy Polyakov 
94481f6075eSEvgeniy Polyakov err_out_clear:
94581f6075eSEvgeniy Polyakov 	usb_set_intfdata(intf, NULL);
94681f6075eSEvgeniy Polyakov 	usb_put_dev(dev->udev);
94781f6075eSEvgeniy Polyakov err_out_free:
94881f6075eSEvgeniy Polyakov 	kfree(dev);
94981f6075eSEvgeniy Polyakov 	return err;
95081f6075eSEvgeniy Polyakov }
95181f6075eSEvgeniy Polyakov 
95281f6075eSEvgeniy Polyakov static void ds_disconnect(struct usb_interface *intf)
95381f6075eSEvgeniy Polyakov {
95481f6075eSEvgeniy Polyakov 	struct ds_device *dev;
95581f6075eSEvgeniy Polyakov 
95681f6075eSEvgeniy Polyakov 	dev = usb_get_intfdata(intf);
95781f6075eSEvgeniy Polyakov 	if (!dev)
95881f6075eSEvgeniy Polyakov 		return;
95981f6075eSEvgeniy Polyakov 
960abd52a13SEvgeniy Polyakov 	mutex_lock(&ds_mutex);
96181f6075eSEvgeniy Polyakov 	list_del(&dev->ds_entry);
962abd52a13SEvgeniy Polyakov 	mutex_unlock(&ds_mutex);
96381f6075eSEvgeniy Polyakov 
96481f6075eSEvgeniy Polyakov 	ds_w1_fini(dev);
96581f6075eSEvgeniy Polyakov 
96681f6075eSEvgeniy Polyakov 	usb_set_intfdata(intf, NULL);
96781f6075eSEvgeniy Polyakov 
96881f6075eSEvgeniy Polyakov 	usb_put_dev(dev->udev);
96981f6075eSEvgeniy Polyakov 	kfree(dev);
97081f6075eSEvgeniy Polyakov }
97181f6075eSEvgeniy Polyakov 
97281f6075eSEvgeniy Polyakov static int ds_init(void)
97381f6075eSEvgeniy Polyakov {
97481f6075eSEvgeniy Polyakov 	int err;
97581f6075eSEvgeniy Polyakov 
97681f6075eSEvgeniy Polyakov 	err = usb_register(&ds_driver);
97781f6075eSEvgeniy Polyakov 	if (err) {
97881f6075eSEvgeniy Polyakov 		printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err);
97981f6075eSEvgeniy Polyakov 		return err;
98081f6075eSEvgeniy Polyakov 	}
98181f6075eSEvgeniy Polyakov 
98281f6075eSEvgeniy Polyakov 	return 0;
98381f6075eSEvgeniy Polyakov }
98481f6075eSEvgeniy Polyakov 
98581f6075eSEvgeniy Polyakov static void ds_fini(void)
98681f6075eSEvgeniy Polyakov {
98781f6075eSEvgeniy Polyakov 	usb_deregister(&ds_driver);
98881f6075eSEvgeniy Polyakov }
98981f6075eSEvgeniy Polyakov 
99081f6075eSEvgeniy Polyakov module_init(ds_init);
99181f6075eSEvgeniy Polyakov module_exit(ds_fini);
99281f6075eSEvgeniy Polyakov 
99381f6075eSEvgeniy Polyakov MODULE_LICENSE("GPL");
99481f6075eSEvgeniy Polyakov MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
99581f6075eSEvgeniy Polyakov MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
996