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

📄 hso.c

📁 linux系统下3G模块USB串口驱动程序源代码最新版本
💻 C
📖 第 1 页 / 共 5 页
字号:
static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file){	int retval;	struct hso_serial *serial = get_serial_by_tty(tty);	struct hso_tiocmget  *tiocmget;	u16 UART_state_bitmap;	/* sanity check */	if (!serial) {		D1("no tty structures");		return -EINVAL;	}	spin_lock_irq(&serial->serial_lock);	retval = ((serial->rts_state) ? TIOCM_RTS : 0) |	    ((serial->dtr_state) ? TIOCM_DTR : 0);	tiocmget = serial->tiocmget;	if (tiocmget) {		UART_state_bitmap = le16_to_cpu(			tiocmget->prev_UART_state_bitmap);		if (UART_state_bitmap & B_RING_SIGNAL)			retval |=  TIOCM_RNG;		if (UART_state_bitmap & B_RX_CARRIER)			retval |=  TIOCM_CD;		if (UART_state_bitmap & B_TX_CARRIER)			retval |=  TIOCM_DSR;	}	spin_unlock_irq(&serial->serial_lock);	return retval;}static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,			       unsigned int set, unsigned int clear){	int val = 0;	unsigned long flags;	int if_num;	struct hso_serial *serial = get_serial_by_tty(tty);	/* sanity check */	if (!serial) {		D1("no tty structures");		return -EINVAL;	}	if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber;	spin_lock_irqsave(&serial->serial_lock, flags);	if (set & TIOCM_RTS)		serial->rts_state = 1;	if (set & TIOCM_DTR)		serial->dtr_state = 1;	if (clear & TIOCM_RTS)		serial->rts_state = 0;	if (clear & TIOCM_DTR)		serial->dtr_state = 0;	if (serial->dtr_state)		val |= 0x01;	if (serial->rts_state)		val |= 0x02;	spin_unlock_irqrestore(&serial->serial_lock, flags);	return usb_control_msg(serial->parent->usb,			       usb_rcvctrlpipe(serial->parent->usb, 0), 0x22,			       0x21, val, if_num, NULL, 0,			       USB_CTRL_SET_TIMEOUT);}/*============================================================================= *	function:	hso_set_radio *	purpose:	Toggles radioon or off ( used by ioctl ) *============================================================================= */#if (!HAVE_RFKILL)static int hso_set_radio(struct hso_device *hso_dev, int enabled){	if (!hso_dev)		return -ENODEV;	return usb_control_msg(	hso_dev->usb,				usb_rcvctrlpipe(hso_dev->usb, 0),				enabled ? 0x82 : 0x81,				0x40, 0, 0, NULL, 0,				USB_CTRL_SET_TIMEOUT);}#endifstatic int hso_serial_ioctl(struct tty_struct *tty, struct file *file,			    unsigned int cmd, unsigned long arg){	struct hso_serial *serial =  get_serial_by_tty(tty);	void __user *uarg = (void __user *)arg;	int ret = 0;	D4("IOCTL cmd: %d, arg: %ld", cmd, arg);	if (!serial)		return -ENODEV;	switch (cmd) {#if (!HAVE_RFKILL)	case SIOCSETRADIO:		if (arg)			hso_set_radio(serial->parent, 1);		else			hso_set_radio(serial->parent, 0);		ret = 0;		break;#endif	case TIOCMIWAIT:		ret = hso_wait_modem_status(serial, arg);		break;	case TIOCGICOUNT:		ret = hso_get_count(serial, uarg);		break;	default:		ret = -ENOIOCTLCMD;		break;	}	return ret;}/* starts a transmit */static void hso_kick_transmit(struct hso_serial *serial){	u8 *temp;	unsigned long flags;	int res;	spin_lock_irqsave(&serial->serial_lock, flags);	if (!serial->tx_buffer_count)		goto out;	if (serial->tx_urb_used)		goto out;#ifdef CONFIG_HSO_AUTOPM	/* Wakeup USB interface if necessary */	if (hso_get_activity(serial->parent) == -EAGAIN)		goto out;#endif	/* Switch pointers around to avoid memcpy */	temp = serial->tx_buffer;	serial->tx_buffer = serial->tx_data;	serial->tx_data = temp;	serial->tx_data_count = serial->tx_buffer_count;	serial->tx_buffer_count = 0;	/* If temp is set, it means we switched buffers */	if (temp && serial->write_data) {		res = serial->write_data(serial);		if (res >= 0)			serial->tx_urb_used = 1;	}out:	spin_unlock_irqrestore(&serial->serial_lock, flags);}/* make a request (for reading and writing data to muxed serial port) */static int mux_device_request(struct hso_serial *serial, u8 type, u16 port,			      struct urb *ctrl_urb,			      struct usb_ctrlrequest *ctrl_req,			      u8 *ctrl_urb_data, u32 size){	int result;	int pipe;	/* Sanity check */	if (!serial || !ctrl_urb || !ctrl_req) {		printk(KERN_ERR "%s: Wrong arguments\n", __func__);		return -EINVAL;	}	/* initialize */	ctrl_req->wValue = 0;	ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port));	ctrl_req->wLength = cpu_to_le16(size);	if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) {		/* Reading command */		ctrl_req->bRequestType = USB_DIR_IN |					 USB_TYPE_OPTION_VENDOR |					 USB_RECIP_INTERFACE;		ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;		pipe = usb_rcvctrlpipe(serial->parent->usb, 0);	} else {		/* Writing command */		ctrl_req->bRequestType = USB_DIR_OUT |					 USB_TYPE_OPTION_VENDOR |					 USB_RECIP_INTERFACE;		ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;		pipe = usb_sndctrlpipe(serial->parent->usb, 0);	}	/* syslog */	D2("%s command (%02x) len: %d, port: %d",	   type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write",	   ctrl_req->bRequestType, ctrl_req->wLength, port);	/* Load ctrl urb */	ctrl_urb->transfer_flags = 0;	usb_fill_control_urb(ctrl_urb,			     serial->parent->usb,			     pipe,			     (u8 *) ctrl_req,			     ctrl_urb_data, size, ctrl_callback, serial);	/* Send it on merry way */	result = usb_submit_urb(ctrl_urb, GFP_ATOMIC);	if (result) {		dev_err(&ctrl_urb->dev->dev,			"%s failed submit ctrl_urb %d type %d\n", __func__,			result, type);		return result;	}	/* done */	return size;}/* called by intr_callback when read occurs */static int hso_mux_serial_read(struct hso_serial *serial){	if (!serial)		return -EINVAL;	/* clean data */	memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE);	/* make the request */	if (serial->num_rx_urbs != 1) {		dev_err(&serial->parent->interface->dev,			"ERROR: mux'd reads with multiple buffers "			"not possible\n");		return 0;	}	return mux_device_request(serial,				  USB_CDC_GET_ENCAPSULATED_RESPONSE,				  serial->parent->port_spec & HSO_PORT_MASK,				  serial->rx_urb[0],				  &serial->ctrl_req_rx,				  serial->rx_data[0], serial->rx_data_length);}/* used for muxed serial port callback (muxed serial read) */static void intr_callback(CALLBACK_ARGS){	struct hso_shared_int *shared_int = urb->context;	struct hso_serial *serial;	unsigned char *port_req;	int status = urb->status;	int i;#ifdef HSO_CONFIG_AUTOPM	usb_mark_last_busy(urb->dev);#endif	/* sanity check */	if (!shared_int)		return;	/* status check */	if (status) {		log_usb_status(status, __func__);		return;	}	D4("\n--- Got intr callback 0x%02X ---", status);	/* what request? */	port_req = urb->transfer_buffer;	D4(" port_req = 0x%.2X\n", *port_req);	/* loop over all muxed ports to find the one sending this */	for (i = 0; i < 8; i++) {		/* max 8 channels on MUX */		if (*port_req & (1 << i)) {			serial = get_serial_by_shared_int_and_type(shared_int,								   (1 << i));			if (serial != NULL) {				D1("Pending read interrupt on port %d\n", i);				spin_lock(&serial->serial_lock);				if (serial->rx_state == RX_IDLE) {					/* Setup and send a ctrl req read on					 * port i */					if (!serial->rx_urb_filled[0]) {						serial->rx_state = RX_SENT;						hso_mux_serial_read(serial);					} else						serial->rx_state = RX_PENDING;				} else {					D1("Already pending a read on "					   "port %d\n", i);				}				spin_unlock(&serial->serial_lock);			}		}	}	/* Resubmit interrupt urb */	hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC);}/* called for writing to muxed serial port */static int hso_mux_serial_write_data(struct hso_serial *serial){	if (NULL == serial)		return -EINVAL;	return mux_device_request(serial,				  USB_CDC_SEND_ENCAPSULATED_COMMAND,				  serial->parent->port_spec & HSO_PORT_MASK,				  serial->tx_urb,				  &serial->ctrl_req_tx,				  serial->tx_data, serial->tx_data_count);}/* write callback for Diag and CS port */static void hso_std_serial_write_bulk_callback(CALLBACK_ARGS){	struct hso_serial *serial = urb->context;	int status = urb->status;	/* sanity check */	if (!serial) {		D1("serial == NULL");		return;	}	spin_lock(&serial->serial_lock);	serial->tx_urb_used = 0;	spin_unlock(&serial->serial_lock);	if (status) {		log_usb_status(status, __func__);		return;	}#ifdef CONFIG_HSO_AUTOPM	hso_put_activity(serial->parent);#endif	if (serial->tty)		tty_wakeup(serial->tty);	hso_kick_transmit(serial);	D1(" ");	return;}/* called for writing diag or CS serial port */static int hso_std_serial_write_data(struct hso_serial *serial){	int count = serial->tx_data_count;	int result;	usb_fill_bulk_urb(serial->tx_urb,			  serial->parent->usb,			  usb_sndbulkpipe(serial->parent->usb,					  serial->out_endp->					  bEndpointAddress & 0x7F),			  serial->tx_data, serial->tx_data_count,			  hso_std_serial_write_bulk_callback, serial);	result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC);	if (result) {		dev_warn(&serial->parent->usb->dev,			 "Failed to submit urb - res %d\n", result);		return result;	}	return count;}/* callback after read or write on muxed serial port */static void ctrl_callback(CALLBACK_ARGS){	struct hso_serial *serial = urb->context;	struct usb_ctrlrequest *req;	int status = urb->status;	/* sanity check */	if (!serial)		return;	spin_lock(&serial->serial_lock);	serial->tx_urb_used = 0;	spin_unlock(&serial->serial_lock);	if (status) {		log_usb_status(status, __func__);		return;	}	/* what request? */	req = (struct usb_ctrlrequest *)(urb->setup_packet);	D4("\n--- Got muxed ctrl callback 0x%02X ---", status);	D4("Actual length of urb = %d\n", urb->actual_length);	DUMP1(urb->transfer_buffer, urb->actual_length);	if (req->bRequestType ==	    (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {		serial->rx_urb_filled[0] = 1;		spin_lock(&serial->serial_lock);		put_rxbuf_data_and_resubmit_ctrl_urb(serial);		spin_unlock(&serial->serial_lock);	} else {#ifdef CONFIG_HSO_AUTOPM		hso_put_activity(serial->parent);#endif		if (serial->tty)			tty_wakeup(serial->tty);		/* response to a write command */		hso_kick_transmit(serial);	}}/* handle RX data for serial port */static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial){	struct tty_struct *tty = serial->tty;	int write_length_remaining = 0;#if (HAVE_TTY_INSERT_FLIP_STRING)	int curr_write_len;#else	int i;	unsigned char *data;#endif	/* Sanity check */	if (urb == NULL || serial == NULL) {		D1("serial = NULL");		return -2;	}	/* Push data to tty */	if (tty) {		write_length_remaining = urb->actual_length -			serial->curr_rx_urb_offset;		D1("data to push to tty");#if (HAVE_TTY_INSERT_FLIP_STRING)		while (write_length_remaining) {			if (test_bit(TTY_THROTTLED, &tty->flags))				return -1;			curr_write_len =  tty_insert_flip_string				(tty, urb->transfer_buffer +				 serial->curr_rx_urb_offset,				 write_length_remaining);			serial->curr_rx_urb_offset += curr_write_len;			write_length_remaining -= curr_write_len;			tty_flip_buffer_push(tty);		}#else		i = 0;		data = urb->transfer_buffer;		for (i = 0; i < write_length_remaining; ++i) {			if (test_bit(TTY_THROTTLED, &tty->flags))				return -1;			if (tty->flip.count >= TTY_FLIPBUF_SIZE)				tty_flip_buffer_push(tty);			tty_insert_flip_char(tty, *(char *)					     ((long)urb->transfer_buffer +					      (long)serial->curr_rx_urb_offset),					     0);			serial->curr_rx_urb_offset++;		}		tty_flip_buffer_push(tty);#endif	}	if (write_length_remaining == 0) {		serial->curr_rx_urb_offset = 0;		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;	}	return write_length_remaining;}/* Base driver functions */static void hso_log_port(struct hso_device *hso_dev){	char *port_type;	char port_dev[20];	switch (hso_dev->port_spec & HSO_PORT_MASK) {	case HSO_PORT_CONTROL:	

⌨️ 快捷键说明

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