cypress_m8.c

来自「linux 内核源代码」· C语言 代码 · 共 1,716 行 · 第 1/4 页

C
1,716
字号
		/* precursor to disconnect so just go away */		return;	case -EPIPE:		usb_clear_halt(port->serial->dev,0x81);		break;	default:		/* something ugly is going on... */		dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",			__FUNCTION__, status);		cypress_set_dead(port);		return;	}	spin_lock_irqsave(&priv->lock, flags);	if (priv->rx_flags & THROTTLED) {		dbg("%s - now throttling", __FUNCTION__);		priv->rx_flags |= ACTUALLY_THROTTLED;		spin_unlock_irqrestore(&priv->lock, flags);		return;	}	spin_unlock_irqrestore(&priv->lock, flags);	tty = port->tty;	if (!tty) {		dbg("%s - bad tty pointer - exiting", __FUNCTION__);		return;	}	spin_lock_irqsave(&priv->lock, flags);	switch(urb->actual_length) {		case 32:			/* This is for the CY7C64013... */			priv->current_status = data[0] & 0xF8;			bytes = data[1] + 2;			i = 2;			if (bytes > 2)				havedata = 1;			break;		case 8:			/* This is for the CY7C63743... */			priv->current_status = data[0] & 0xF8;			bytes = (data[0] & 0x07) + 1;			i = 1;			if (bytes > 1)				havedata = 1;			break;		default:			dbg("%s - wrong packet size - received %d bytes",					__FUNCTION__, urb->actual_length);			spin_unlock_irqrestore(&priv->lock, flags);			goto continue_read;	}	spin_unlock_irqrestore(&priv->lock, flags);	usb_serial_debug_data (debug, &port->dev, __FUNCTION__,			urb->actual_length, data);	spin_lock_irqsave(&priv->lock, flags);	/* check to see if status has changed */	if (priv != NULL) {		if (priv->current_status != priv->prev_status) {			priv->diff_status |= priv->current_status ^				priv->prev_status;			wake_up_interruptible(&priv->delta_msr_wait);			priv->prev_status = priv->current_status;		}	}	spin_unlock_irqrestore(&priv->lock, flags);	/* hangup, as defined in acm.c... this might be a bad place for it	 * though */	if (tty && !(tty->termios->c_cflag & CLOCAL) &&			!(priv->current_status & UART_CD)) {		dbg("%s - calling hangup", __FUNCTION__);		tty_hangup(tty);		goto continue_read;	}	/* There is one error bit... I'm assuming it is a parity error	 * indicator as the generic firmware will set this bit to 1 if a	 * parity error occurs.	 * I can not find reference to any other error events. */	spin_lock_irqsave(&priv->lock, flags);	if (priv->current_status & CYP_ERROR) {		spin_unlock_irqrestore(&priv->lock, flags);		tty_flag = TTY_PARITY;		dbg("%s - Parity Error detected", __FUNCTION__);	} else		spin_unlock_irqrestore(&priv->lock, flags);	/* process read if there is data other than line status */	if (tty && (bytes > i)) {		bytes = tty_buffer_request_room(tty, bytes);		for (; i < bytes ; ++i) {			dbg("pushing byte number %d - %d - %c", i, data[i],					data[i]);			tty_insert_flip_char(tty, data[i], tty_flag);		}		tty_flip_buffer_push(port->tty);	}	spin_lock_irqsave(&priv->lock, flags);	/* control and status byte(s) are also counted */	priv->bytes_in += bytes;	spin_unlock_irqrestore(&priv->lock, flags);continue_read:	/* Continue trying to always read... unless the port has closed. */	if (port->open_count > 0 && priv->comm_is_ok) {		usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,				usb_rcvintpipe(port->serial->dev,					port->interrupt_in_endpointAddress),				port->interrupt_in_urb->transfer_buffer,				port->interrupt_in_urb->transfer_buffer_length,				cypress_read_int_callback, port, priv->read_urb_interval);		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);		if (result) {			dev_err(&urb->dev->dev, "%s - failed resubmitting "					"read urb, error %d\n", __FUNCTION__,					result);			cypress_set_dead(port);		}	}	return;} /* cypress_read_int_callback */static void cypress_write_int_callback(struct urb *urb){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct cypress_private *priv = usb_get_serial_port_data(port);	int result;	int status = urb->status;	dbg("%s - port %d", __FUNCTION__, port->number);	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);			priv->write_urb_in_use = 0;			return;		case -EPIPE: /* no break needed; clear halt and resubmit */			if (!priv->comm_is_ok)				break;			usb_clear_halt(port->serial->dev, 0x02);			/* error in the urb, so we have to resubmit it */			dbg("%s - nonzero write bulk status received: %d",			    __FUNCTION__, status);			port->interrupt_out_urb->transfer_buffer_length = 1;			port->interrupt_out_urb->dev = port->serial->dev;			result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);			if (!result)				return;			dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",				__FUNCTION__, result);			cypress_set_dead(port);			break;		default:			dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",				__FUNCTION__, status);			cypress_set_dead(port);			break;	}		priv->write_urb_in_use = 0;		/* send any buffered data */	cypress_send(port);}/***************************************************************************** * Write buffer functions - buffering code from pl2303 used *****************************************************************************//* * cypress_buf_alloc * * Allocate a circular buffer and all associated memory. */static struct cypress_buf *cypress_buf_alloc(unsigned int size){	struct cypress_buf *cb;	if (size == 0)		return NULL;	cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL);	if (cb == NULL)		return NULL;	cb->buf_buf = kmalloc(size, GFP_KERNEL);	if (cb->buf_buf == NULL) {		kfree(cb);		return NULL;	}	cb->buf_size = size;	cb->buf_get = cb->buf_put = cb->buf_buf;	return cb;}/* * cypress_buf_free * * Free the buffer and all associated memory. */static void cypress_buf_free(struct cypress_buf *cb){	if (cb) {		kfree(cb->buf_buf);		kfree(cb);	}}/* * cypress_buf_clear * * Clear out all data in the circular buffer. */static void cypress_buf_clear(struct cypress_buf *cb){	if (cb != NULL)		cb->buf_get = cb->buf_put;		/* equivalent to a get of all data available */}/* * cypress_buf_data_avail * * Return the number of bytes of data available in the circular * buffer. */static unsigned int cypress_buf_data_avail(struct cypress_buf *cb){	if (cb != NULL)		return ((cb->buf_size + cb->buf_put - cb->buf_get) % cb->buf_size);	else		return 0;}/* * cypress_buf_space_avail * * Return the number of bytes of space available in the circular * buffer. */static unsigned int cypress_buf_space_avail(struct cypress_buf *cb){	if (cb != NULL)		return ((cb->buf_size + cb->buf_get - cb->buf_put - 1) % cb->buf_size);	else		return 0;}/* * cypress_buf_put * * Copy data data from a user buffer and put it into the circular buffer. * Restrict to the amount of space available. * * Return the number of bytes copied. */static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf,	unsigned int count){	unsigned int len;	if (cb == NULL)		return 0;	len  = cypress_buf_space_avail(cb);	if (count > len)		count = len;	if (count == 0)		return 0;	len = cb->buf_buf + cb->buf_size - cb->buf_put;	if (count > len) {		memcpy(cb->buf_put, buf, len);		memcpy(cb->buf_buf, buf+len, count - len);		cb->buf_put = cb->buf_buf + count - len;	} else {		memcpy(cb->buf_put, buf, count);		if (count < len)			cb->buf_put += count;		else /* count == len */			cb->buf_put = cb->buf_buf;	}	return count;}/* * cypress_buf_get * * Get data from the circular buffer and copy to the given buffer. * Restrict to the amount of data available. * * Return the number of bytes copied. */static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf,	unsigned int count){	unsigned int len;	if (cb == NULL)		return 0;	len = cypress_buf_data_avail(cb);	if (count > len)		count = len;	if (count == 0)		return 0;	len = cb->buf_buf + cb->buf_size - cb->buf_get;	if (count > len) {		memcpy(buf, cb->buf_get, len);		memcpy(buf+len, cb->buf_buf, count - len);		cb->buf_get = cb->buf_buf + count - len;	} else {		memcpy(buf, cb->buf_get, count);		if (count < len)			cb->buf_get += count;		else /* count == len */			cb->buf_get = cb->buf_buf;	}	return count;}/***************************************************************************** * Module functions *****************************************************************************/static int __init cypress_init(void){	int retval;		dbg("%s", __FUNCTION__);		retval = usb_serial_register(&cypress_earthmate_device);	if (retval)		goto failed_em_register;	retval = usb_serial_register(&cypress_hidcom_device);	if (retval)		goto failed_hidcom_register;	retval = usb_serial_register(&cypress_ca42v2_device);	if (retval)		goto failed_ca42v2_register;	retval = usb_register(&cypress_driver);	if (retval)		goto failed_usb_register;	info(DRIVER_DESC " " DRIVER_VERSION);	return 0;failed_usb_register:	usb_serial_deregister(&cypress_ca42v2_device);failed_ca42v2_register:	usb_serial_deregister(&cypress_hidcom_device);failed_hidcom_register:	usb_serial_deregister(&cypress_earthmate_device);failed_em_register:	return retval;}static void __exit cypress_exit (void){	dbg("%s", __FUNCTION__);	usb_deregister (&cypress_driver);	usb_serial_deregister (&cypress_earthmate_device);	usb_serial_deregister (&cypress_hidcom_device);	usb_serial_deregister (&cypress_ca42v2_device);}module_init(cypress_init);module_exit(cypress_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_VERSION( DRIVER_VERSION );MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");module_param(stats, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(stats, "Enable statistics or not");module_param(interval, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(interval, "Overrides interrupt interval");

⌨️ 快捷键说明

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