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

📄 mos7720.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * mos7720.c *   Controls the Moschip 7720 usb to dual port serial convertor * * Copyright 2006 Moschip Semiconductor Tech. Ltd. * * 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, version 2 of the License. * * Developed by: * 	Vijaya Kumar <vijaykumar.gn@gmail.com> *	Ajay Kumar <naanuajay@yahoo.com> *	Gurudeva <ngurudeva@yahoo.com> * * Cleaned up from the original by: *	Greg Kroah-Hartman <gregkh@suse.de> * * Originally based on drivers/usb/serial/io_edgeport.c which is: *	Copyright (C) 2000 Inside Out Networks, All rights reserved. *	Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> */#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 <linux/serial.h>#include <linux/serial_reg.h>#include <linux/usb.h>#include <linux/usb/serial.h>#include <asm/uaccess.h>/* * Version Information */#define DRIVER_VERSION "1.0.0.4F"#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."#define DRIVER_DESC "Moschip USB Serial Driver"/* default urb timeout */#define MOS_WDR_TIMEOUT	(HZ * 5)#define MOS_PORT1	0x0200#define MOS_PORT2	0x0300#define MOS_VENREG	0x0000#define MOS_MAX_PORT	0x02#define MOS_WRITE	0x0E#define MOS_READ	0x0D/* Interrupt Rotinue Defines	*/#define SERIAL_IIR_RLS	0x06#define SERIAL_IIR_RDA	0x04#define SERIAL_IIR_CTI	0x0c#define SERIAL_IIR_THR	0x02#define SERIAL_IIR_MS	0x00#define NUM_URBS			16	/* URB Count */#define URB_TRANSFER_BUFFER_SIZE	32	/* URB Size *//* This structure holds all of the local port information */struct moschip_port{	__u8	shadowLCR;		/* last LCR value received */	__u8	shadowMCR;		/* last MCR value received */	__u8	shadowMSR;		/* last MSR value received */	char			open;	struct async_icount	icount;	struct usb_serial_port	*port;	/* loop back to the owner */	struct urb		*write_urb_pool[NUM_URBS];};/* This structure holds all of the individual serial device information */struct moschip_serial{	int interrupt_started;};static int debug;#define USB_VENDOR_ID_MOSCHIP		0x9710#define MOSCHIP_DEVICE_ID_7720		0x7720#define MOSCHIP_DEVICE_ID_7715		0x7715static struct usb_device_id moschip_port_id_table [] = {	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },	{ } /* terminating entry */};MODULE_DEVICE_TABLE(usb, moschip_port_id_table);/* * mos7720_interrupt_callback *	this is the callback function for when we have received data on the *	interrupt endpoint. */static void mos7720_interrupt_callback(struct urb *urb){	int result;	int length;	int status = urb->status;	__u8 *data;	__u8 sp1;	__u8 sp2;	dbg("%s"," : Entering\n");	switch (status) {	case 0:		/* success */		break;	case -ECONNRESET:	case -ENOENT:	case -ESHUTDOWN:		/* this urb is terminated, clean up */		dbg("%s - urb shutting down with status: %d", __FUNCTION__,		    status);		return;	default:		dbg("%s - nonzero urb status received: %d", __FUNCTION__,		    status);		goto exit;	}	length = urb->actual_length;	data = urb->transfer_buffer;	/* Moschip get 4 bytes	 * Byte 1 IIR Port 1 (port.number is 0)	 * Byte 2 IIR Port 2 (port.number is 1)	 * Byte 3 --------------	 * Byte 4 FIFO status for both */	/* the above description is inverted	 * 	oneukum 2007-03-14 */	if (unlikely(length != 4)) {		dbg("Wrong data !!!");		return;	}	sp1 = data[3];	sp2 = data[2];	if ((sp1 | sp2) & 0x01) {		/* No Interrupt Pending in both the ports */		dbg("No Interrupt !!!");	} else {		switch (sp1 & 0x0f) {		case SERIAL_IIR_RLS:			dbg("Serial Port 1: Receiver status error or address "			    "bit detected in 9-bit mode\n");			break;		case SERIAL_IIR_CTI:			dbg("Serial Port 1: Receiver time out");			break;		case SERIAL_IIR_MS:			dbg("Serial Port 1: Modem status change");			break;		}		switch (sp2 & 0x0f) {		case SERIAL_IIR_RLS:			dbg("Serial Port 2: Receiver status error or address "			    "bit detected in 9-bit mode");			break;		case SERIAL_IIR_CTI:			dbg("Serial Port 2: Receiver time out");			break;		case SERIAL_IIR_MS:			dbg("Serial Port 2: Modem status change");			break;		}	}exit:	result = usb_submit_urb(urb, GFP_ATOMIC);	if (result)		dev_err(&urb->dev->dev,			"%s - Error %d submitting control urb\n",			__FUNCTION__, result);	return;}/* * mos7720_bulk_in_callback *	this is the callback function for when we have received data on the *	bulk in endpoint. */static void mos7720_bulk_in_callback(struct urb *urb){	int retval;	unsigned char *data ;	struct usb_serial_port *port;	struct moschip_port *mos7720_port;	struct tty_struct *tty;	int status = urb->status;	if (status) {		dbg("nonzero read bulk status received: %d", status);		return;	}	mos7720_port = urb->context;	if (!mos7720_port) {		dbg("%s","NULL mos7720_port pointer \n");		return ;	}	port = mos7720_port->port;	dbg("Entering...%s", __FUNCTION__);	data = urb->transfer_buffer;	tty = port->tty;	if (tty && urb->actual_length) {		tty_buffer_request_room(tty, urb->actual_length);		tty_insert_flip_string(tty, data, urb->actual_length);		tty_flip_buffer_push(tty);	}	if (!port->read_urb) {		dbg("URB KILLED !!!");		return;	}	if (port->read_urb->status != -EINPROGRESS) {		port->read_urb->dev = port->serial->dev;		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);		if (retval)			dbg("usb_submit_urb(read bulk) failed, retval = %d",			    retval);	}}/* * mos7720_bulk_out_data_callback *	this is the callback function for when we have finished sending serial *	data on the bulk out endpoint. */static void mos7720_bulk_out_data_callback(struct urb *urb){	struct moschip_port *mos7720_port;	struct tty_struct *tty;	int status = urb->status;	if (status) {		dbg("nonzero write bulk status received:%d", status);		return;	}	mos7720_port = urb->context;	if (!mos7720_port) {		dbg("NULL mos7720_port pointer");		return ;	}	dbg("Entering .........");	tty = mos7720_port->port->tty;	if (tty && mos7720_port->open)		tty_wakeup(tty);}/* * send_mos_cmd *	this function will be used for sending command to device */static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,			__u16 index, void *data){	int status;	unsigned int pipe;	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);	__u8 requesttype;	__u16 size = 0x0000;	if (value < MOS_MAX_PORT) {		if (product == MOSCHIP_DEVICE_ID_7715) {			value = value*0x100+0x100;		} else {			value = value*0x100+0x200;		}	} else {		value = 0x0000;		if ((product == MOSCHIP_DEVICE_ID_7715) &&		    (index != 0x08)) {			dbg("serial->product== MOSCHIP_DEVICE_ID_7715");			//index = 0x01 ;		}	}	if (request == MOS_WRITE) {		request = (__u8)MOS_WRITE;		requesttype = (__u8)0x40;		value  = value + (__u16)*((unsigned char *)data);		data = NULL;		pipe = usb_sndctrlpipe(serial->dev, 0);	} else {		request = (__u8)MOS_READ;		requesttype = (__u8)0xC0;		size = 0x01;		pipe = usb_rcvctrlpipe(serial->dev,0);	}	status = usb_control_msg(serial->dev, pipe, request, requesttype,				 value, index, data, size, MOS_WDR_TIMEOUT);	if (status < 0)		dbg("Command Write failed Value %x index %x\n",value,index);	return status;}static int mos7720_open(struct usb_serial_port *port, struct file * filp){	struct usb_serial *serial;	struct usb_serial_port *port0;	struct urb *urb;	struct moschip_serial *mos7720_serial;	struct moschip_port *mos7720_port;	int response;	int port_number;	char data;	int allocated_urbs = 0;	int j;	serial = port->serial;	mos7720_port = usb_get_serial_port_data(port);	if (mos7720_port == NULL)		return -ENODEV;	port0 = serial->port[0];	mos7720_serial = usb_get_serial_data(serial);	if (mos7720_serial == NULL || port0 == NULL)		return -ENODEV;	usb_clear_halt(serial->dev, port->write_urb->pipe);	usb_clear_halt(serial->dev, port->read_urb->pipe);	/* Initialising the write urb pool */	for (j = 0; j < NUM_URBS; ++j) {		urb = usb_alloc_urb(0,GFP_KERNEL);		mos7720_port->write_urb_pool[j] = urb;		if (urb == NULL) {			err("No more urbs???");			continue;		}		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,					       GFP_KERNEL);		if (!urb->transfer_buffer) {			err("%s-out of memory for urb buffers.", __FUNCTION__);			usb_free_urb(mos7720_port->write_urb_pool[j]);			mos7720_port->write_urb_pool[j] = NULL;			continue;		}		allocated_urbs++;	}	if (!allocated_urbs)		return -ENOMEM;	 /* Initialize MCS7720 -- Write Init values to corresponding Registers	  *	  * Register Index	  * 1 : IER	  * 2 : FCR	  * 3 : LCR	  * 4 : MCR	  *	  * 0x08 : SP1/2 Control Reg	  */	port_number = port->number - port->serial->minor;	send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);	dbg("SS::%p LSR:%x\n",mos7720_port, data);	dbg("Check:Sending Command ..........");	data = 0x02;	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);	data = 0x02;	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);	data = 0x00;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);	data = 0x00;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);	data = 0xCF;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);	data = 0x03;        mos7720_port->shadowLCR  = data;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);	data = 0x0b;        mos7720_port->shadowMCR  = data;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);	data = 0x0b;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);	data = 0x00;	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);	data = 0x00;	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);/*	data = 0x00;	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);	data = 0x03;	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);	data = 0x00;	send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);*/	data = 0x00;	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);	data = data | (port->number - port->serial->minor + 1);	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);	data = 0x83;        mos7720_port->shadowLCR  = data;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);	data = 0x0c;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);	data = 0x00;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);	data = 0x03;        mos7720_port->shadowLCR  = data;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);	data = 0x0c;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);	data = 0x0c;	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);//Matrix	/* force low_latency on so that our tty_push actually forces *	 * the data through,otherwise it is scheduled, and with      *	 * high data rates (like with OHCI) data can get lost.       */	if (port->tty)		port->tty->low_latency = 1;	/* see if we've set up our endpoint info yet   *	 * (can't set it up in mos7720_startup as the  *	 * structures were not set up at that time.)   */	if (!mos7720_serial->interrupt_started) {		dbg("Interrupt buffer NULL !!!");		/* not set up yet, so do it now */		mos7720_serial->interrupt_started = 1;		dbg("To Submit URB !!!");		/* set up our interrupt urb */		usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,				 usb_rcvintpipe(serial->dev,				 		port->interrupt_in_endpointAddress),				 port0->interrupt_in_buffer,				 port0->interrupt_in_urb->transfer_buffer_length,				 mos7720_interrupt_callback, mos7720_port,				 port0->interrupt_in_urb->interval);		/* start interrupt read for this mos7720 this interrupt *	         * will continue as long as the mos7720 is connected    */		dbg("Submit URB over !!!");		response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);		if (response)			dev_err(&port->dev,				"%s - Error %d submitting control urb\n",				__FUNCTION__, response);	}	/* set up our bulk in urb */	usb_fill_bulk_urb(port->read_urb, serial->dev,			  usb_rcvbulkpipe(serial->dev,			  		  port->bulk_in_endpointAddress),			  port->bulk_in_buffer,			  port->read_urb->transfer_buffer_length,			  mos7720_bulk_in_callback, mos7720_port);	response = usb_submit_urb(port->read_urb, GFP_KERNEL);	if (response)		dev_err(&port->dev,			"%s - Error %d submitting read urb\n", __FUNCTION__, response);	/* initialize our icount structure */	memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));	/* initialize our port settings */	mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */	/* send a open port command */	mos7720_port->open = 1;	return 0;}/* * mos7720_chars_in_buffer *	this function is called by the tty driver when it wants to know how many *	bytes of data we currently have outstanding in the port (data that has *	been written, but hasn't made it out the port yet) *	If successful, we return the number of bytes left to be written in the *	system, *	Otherwise we return a negative error number. */static int mos7720_chars_in_buffer(struct usb_serial_port *port){	int i;	int chars = 0;	struct moschip_port *mos7720_port;	dbg("%s:entering ...........", __FUNCTION__);	mos7720_port = usb_get_serial_port_data(port);	if (mos7720_port == NULL) {		dbg("%s:leaving ...........", __FUNCTION__);		return -ENODEV;	}	for (i = 0; i < NUM_URBS; ++i) {		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)			chars += URB_TRANSFER_BUFFER_SIZE;	}	dbg("%s - returns %d", __FUNCTION__, chars);	return chars;}static void mos7720_close(struct usb_serial_port *port, struct file *filp){	struct usb_serial *serial;	struct moschip_port *mos7720_port;	char data;	int j;	dbg("mos7720_close:entering...");	serial = port->serial;	mos7720_port = usb_get_serial_port_data(port);	if (mos7720_port == NULL)		return;	for (j = 0; j < NUM_URBS; ++j)		usb_kill_urb(mos7720_port->write_urb_pool[j]);

⌨️ 快捷键说明

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