⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 whiteheat.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * USB ConnectTech WhiteHEAT driver * *	Copyright (C) 2002 *	    Connect Tech Inc. * *	Copyright (C) 1999 - 2001 *	    Greg Kroah-Hartman (greg@kroah.com) * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver * * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com) *	Upgrade to full working driver * * (05/30/2001) gkh *	switched from using spinlock to a semaphore, which fixes lots of problems. * * (04/08/2001) gb *	Identify version on module load. *  * 2001_Mar_19 gkh *	Fixed MOD_INC and MOD_DEC logic, the ability to open a port more  *	than once, and the got the proper usb_device_id table entries so *	the driver works again. * * (11/01/2000) Adam J. Richter *	usb_device_id table support *  * (10/05/2000) gkh *	Fixed bug with urb->dev not being set properly, now that the usb *	core needs it. *  * (10/03/2000) smd *	firmware is improved to guard against crap sent to device *	firmware now replies CMD_FAILURE on bad things *	read_callback fix you provided for private info struct *	command_finished now indicates success or fail *	setup_port struct now packed to avoid gcc padding *	firmware uses 1 based port numbering, driver now handles that * * (09/11/2000) gkh *	Removed DEBUG #ifdefs with call to usb_serial_debug_data * * (07/19/2000) gkh *	Added module_init and module_exit functions to handle the fact that this *	driver is a loadable module now. *	Fixed bug with port->minor that was found by Al Borchers * * (07/04/2000) gkh *	Added support for port settings. Baud rate can now be changed. Line signals *	are not transferred to and from the tty layer yet, but things seem to be  *	working well now. * * (05/04/2000) gkh *	First cut at open and close commands. Data can flow through the ports at *	default speeds now. * * (03/26/2000) gkh *	Split driver up into device specific pieces. *  */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <asm/termbits.h>#include <linux/usb.h>#include <linux/serial_reg.h>#include <linux/serial.h>#include "usb-serial.h"#include "whiteheat_fw.h"		/* firmware for the ConnectTech WhiteHEAT device */#include "whiteheat.h"			/* WhiteHEAT specific commands */static int debug;#ifndef CMSPAR#define CMSPAR 0#endif/* * Version Information */#define DRIVER_VERSION "v2.0"#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"#define CONNECT_TECH_VENDOR_ID		0x0710#define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001#define CONNECT_TECH_WHITE_HEAT_ID	0x8001/*   ID tables for whiteheat are unusual, because we want to different   things for different versions of the device.  Eventually, this   will be doable from a single table.  But, for now, we define two   separate ID tables, and then a third table that combines them   just for the purpose of exporting the autoloading information.*/static struct usb_device_id id_table_std [] = {	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },	{ }						/* Terminating entry */};static struct usb_device_id id_table_prerenumeration [] = {	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },	{ }						/* Terminating entry */};static struct usb_device_id id_table_combined [] = {	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },	{ }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);static struct usb_driver whiteheat_driver = {	.owner =	THIS_MODULE,	.name =		"whiteheat",	.probe =	usb_serial_probe,	.disconnect =	usb_serial_disconnect,	.id_table =	id_table_combined,};/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */static int  whiteheat_firmware_download	(struct usb_serial *serial, const struct usb_device_id *id);static int  whiteheat_firmware_attach	(struct usb_serial *serial);/* function prototypes for the Connect Tech WhiteHEAT serial converter */static int  whiteheat_attach		(struct usb_serial *serial);static void whiteheat_shutdown		(struct usb_serial *serial);static int  whiteheat_open		(struct usb_serial_port *port, struct file *filp);static void whiteheat_close		(struct usb_serial_port *port, struct file *filp);static int  whiteheat_write		(struct usb_serial_port *port, const unsigned char *buf, int count);static int  whiteheat_write_room	(struct usb_serial_port *port);static int  whiteheat_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);static void whiteheat_set_termios	(struct usb_serial_port *port, struct termios * old);static int  whiteheat_tiocmget		(struct usb_serial_port *port, struct file *file);static int  whiteheat_tiocmset		(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);static void whiteheat_break_ctl		(struct usb_serial_port *port, int break_state);static int  whiteheat_chars_in_buffer	(struct usb_serial_port *port);static void whiteheat_throttle		(struct usb_serial_port *port);static void whiteheat_unthrottle	(struct usb_serial_port *port);static void whiteheat_read_callback	(struct urb *urb, struct pt_regs *regs);static void whiteheat_write_callback	(struct urb *urb, struct pt_regs *regs);static struct usb_serial_driver whiteheat_fake_device = {	.driver = {		.owner =	THIS_MODULE,		.name =		"whiteheatnofirm",	},	.description =		"Connect Tech - WhiteHEAT - (prerenumeration)",	.id_table =		id_table_prerenumeration,	.num_interrupt_in =	NUM_DONT_CARE,	.num_bulk_in =		NUM_DONT_CARE,	.num_bulk_out =		NUM_DONT_CARE,	.num_ports =		1,	.probe =		whiteheat_firmware_download,	.attach =		whiteheat_firmware_attach,};static struct usb_serial_driver whiteheat_device = {	.driver = {		.owner =	THIS_MODULE,		.name =		"whiteheat",	},	.description =		"Connect Tech - WhiteHEAT",	.id_table =		id_table_std,	.num_interrupt_in =	NUM_DONT_CARE,	.num_bulk_in =		NUM_DONT_CARE,	.num_bulk_out =		NUM_DONT_CARE,	.num_ports =		4,	.attach =		whiteheat_attach,	.shutdown =		whiteheat_shutdown,	.open =			whiteheat_open,	.close =		whiteheat_close,	.write =		whiteheat_write,	.write_room =		whiteheat_write_room,	.ioctl =		whiteheat_ioctl,	.set_termios =		whiteheat_set_termios,	.break_ctl =		whiteheat_break_ctl,	.tiocmget =		whiteheat_tiocmget,	.tiocmset =		whiteheat_tiocmset,	.chars_in_buffer =	whiteheat_chars_in_buffer,	.throttle =		whiteheat_throttle,	.unthrottle =		whiteheat_unthrottle,	.read_bulk_callback =	whiteheat_read_callback,	.write_bulk_callback =	whiteheat_write_callback,};struct whiteheat_command_private {	spinlock_t		lock;	__u8			port_running;	__u8			command_finished;	wait_queue_head_t	wait_command;	/* for handling sleeping while waiting for a command to finish */	__u8			result_buffer[64];};#define THROTTLED		0x01#define ACTUALLY_THROTTLED	0x02static int urb_pool_size = 8;struct whiteheat_urb_wrap {	struct list_head	list;	struct urb		*urb;};struct whiteheat_private {	spinlock_t		lock;	__u8			flags;	__u8			mcr;	struct list_head	rx_urbs_free;	struct list_head	rx_urbs_submitted;	struct list_head	rx_urb_q;	struct work_struct	rx_work;	struct list_head	tx_urbs_free;	struct list_head	tx_urbs_submitted;};/* local function prototypes */static int start_command_port(struct usb_serial *serial);static void stop_command_port(struct usb_serial *serial);static void command_port_write_callback(struct urb *urb, struct pt_regs *regs);static void command_port_read_callback(struct urb *urb, struct pt_regs *regs);static int start_port_read(struct usb_serial_port *port);static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head);static struct list_head *list_first(struct list_head *head);static void rx_data_softint(void *private);static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize);static int firm_open(struct usb_serial_port *port);static int firm_close(struct usb_serial_port *port);static int firm_setup_port(struct usb_serial_port *port);static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);static int firm_set_break(struct usb_serial_port *port, __u8 onoff);static int firm_purge(struct usb_serial_port *port, __u8 rxtx);static int firm_get_dtr_rts(struct usb_serial_port *port);static int firm_report_tx_done(struct usb_serial_port *port);#define COMMAND_PORT		4#define COMMAND_TIMEOUT		(2*HZ)	/* 2 second timeout for a command */#define	COMMAND_TIMEOUT_MS	2000#define CLOSING_DELAY		(30 * HZ)/***************************************************************************** * Connect Tech's White Heat prerenumeration driver functions *****************************************************************************//* steps to download the firmware to the WhiteHEAT device: - hold the reset (by writing to the reset bit of the CPUCS register) - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD - release the reset (by writing to the CPUCS register) - download the WH.HEX file for all addresses greater than 0x1b3f using   VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD - hold the reset - download the WH.HEX file for all addresses less than 0x1b40 using   VENDOR_REQUEST_ANCHOR_LOAD - release the reset - device renumerated itself and comes up as new device id with all   firmware download completed.*/static int whiteheat_firmware_download (struct usb_serial *serial, const struct usb_device_id *id){	int response;	const struct whiteheat_hex_record *record;		dbg("%s", __FUNCTION__);		response = ezusb_set_reset (serial, 1);	record = &whiteheat_loader[0];	while (record->address != 0xffff) {		response = ezusb_writememory (serial, record->address, 				(unsigned char *)record->data, record->data_size, 0xa0);		if (response < 0) {			err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",				__FUNCTION__, response, record->address, record->data, record->data_size);			break;		}		++record;	}	response = ezusb_set_reset (serial, 0);	record = &whiteheat_firmware[0];	while (record->address < 0x1b40) {		++record;	}	while (record->address != 0xffff) {		response = ezusb_writememory (serial, record->address, 				(unsigned char *)record->data, record->data_size, 0xa3);		if (response < 0) {			err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 				__FUNCTION__, response, record->address, record->data, record->data_size);			break;		}		++record;	}		response = ezusb_set_reset (serial, 1);	record = &whiteheat_firmware[0];	while (record->address < 0x1b40) {		response = ezusb_writememory (serial, record->address, 				(unsigned char *)record->data, record->data_size, 0xa0);		if (response < 0) {			err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 				__FUNCTION__, response, record->address, record->data, record->data_size);			break;		}		++record;	}	response = ezusb_set_reset (serial, 0);	return 0;}static int whiteheat_firmware_attach (struct usb_serial *serial){	/* We want this device to fail to have a driver assigned to it */	return 1;}/***************************************************************************** * Connect Tech's White Heat serial driver functions *****************************************************************************/static int whiteheat_attach (struct usb_serial *serial){	struct usb_serial_port *command_port;	struct whiteheat_command_private *command_info;	struct usb_serial_port *port;	struct whiteheat_private *info;	struct whiteheat_hw_info *hw_info;	int pipe;	int ret;	int alen;	__u8 *command;	__u8 *result;	int i;	int j;	struct urb *urb;	int buf_size;	struct whiteheat_urb_wrap *wrap;	struct list_head *tmp;	command_port = serial->port[COMMAND_PORT];	pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress);	command = kmalloc(2, GFP_KERNEL);	if (!command)		goto no_command_buffer;	command[0] = WHITEHEAT_GET_HW_INFO;	command[1] = 0;		result = kmalloc(sizeof(*hw_info) + 1, GFP_KERNEL);	if (!result)		goto no_result_buffer;	/*	 * When the module is reloaded the firmware is still there and	 * the endpoints are still in the usb core unchanged. This is the         * unlinking bug in disguise. Same for the call below.         */	usb_clear_halt(serial->dev, pipe);	ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS);	if (ret) {		err("%s: Couldn't send command [%d]", serial->type->description, ret);		goto no_firmware;	} else if (alen != sizeof(command)) {		err("%s: Send command incomplete [%d]", serial->type->description, alen);		goto no_firmware;	}	pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress);	/* See the comment on the usb_clear_halt() above */	usb_clear_halt(serial->dev, pipe);	ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);	if (ret) {		err("%s: Couldn't get results [%d]", serial->type->description, ret);		goto no_firmware;	} else if (alen != sizeof(result)) {		err("%s: Get results incomplete [%d]", serial->type->description, alen);		goto no_firmware;	} else if (result[0] != command[0]) {		err("%s: Command failed [%d]", serial->type->description, result[0]);		goto no_firmware;	}	hw_info = (struct whiteheat_hw_info *)&result[1];	info("%s: Driver %s: Firmware v%d.%02d", serial->type->description,	     DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);	for (i = 0; i < serial->num_ports; i++) {		port = serial->port[i];		info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);		if (info == NULL) {			err("%s: Out of memory for port structures\n", serial->type->description);			goto no_private;		}		spin_lock_init(&info->lock);		info->flags = 0;		info->mcr = 0;		INIT_WORK(&info->rx_work, rx_data_softint, port);		INIT_LIST_HEAD(&info->rx_urbs_free);		INIT_LIST_HEAD(&info->rx_urbs_submitted);		INIT_LIST_HEAD(&info->rx_urb_q);		INIT_LIST_HEAD(&info->tx_urbs_free);		INIT_LIST_HEAD(&info->tx_urbs_submitted);		for (j = 0; j < urb_pool_size; j++) {			urb = usb_alloc_urb(0, GFP_KERNEL);			if (!urb) {				err("No free urbs available");				goto no_rx_urb;			}			buf_size = port->read_urb->transfer_buffer_length;			urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);			if (!urb->transfer_buffer) {				err("Couldn't allocate urb buffer");				goto no_rx_buf;			}			wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);			if (!wrap) {				err("Couldn't allocate urb wrapper");				goto no_rx_wrap;			}			usb_fill_bulk_urb(urb, serial->dev,					usb_rcvbulkpipe(serial->dev,						port->bulk_in_endpointAddress),					urb->transfer_buffer, buf_size,					whiteheat_read_callback, port);			wrap->urb = urb;			list_add(&wrap->list, &info->rx_urbs_free);			urb = usb_alloc_urb(0, GFP_KERNEL);			if (!urb) {				err("No free urbs available");				goto no_tx_urb;			}			buf_size = port->write_urb->transfer_buffer_length;			urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);			if (!urb->transfer_buffer) {				err("Couldn't allocate urb buffer");				goto no_tx_buf;			}			wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);			if (!wrap) {				err("Couldn't allocate urb wrapper");				goto no_tx_wrap;			}			usb_fill_bulk_urb(urb, serial->dev,					usb_sndbulkpipe(serial->dev,						port->bulk_out_endpointAddress),					urb->transfer_buffer, buf_size,					whiteheat_write_callback, port);			wrap->urb = urb;			list_add(&wrap->list, &info->tx_urbs_free);		}		usb_set_serial_port_data(port, info);	}	command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL);	if (command_info == NULL) {		err("%s: Out of memory for port structures\n", serial->type->description);		goto no_command_private;	}	spin_lock_init(&command_info->lock);	command_info->port_running = 0;	init_waitqueue_head(&command_info->wait_command);	usb_set_serial_port_data(command_port, command_info);	command_port->write_urb->complete = command_port_write_callback;	command_port->read_urb->complete = command_port_read_callback;	kfree(result);	kfree(command);	return 0;no_firmware:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -