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

📄 hso.c

📁 linux系统下3G模块USB串口驱动程序源代码最新版本
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}}static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial){	int count = 0;	struct urb *urb;	urb = serial->rx_urb[0];	if (serial->open_count > 0) {		count = put_rxbuf_data(urb, serial);		if (count == -1)			return;	}	/* Re issue a read as long as we receive data. */	if (count == 0 && ((urb->actual_length != 0) ||			   (serial->rx_state == RX_PENDING))) {		serial->rx_state = RX_SENT;		hso_mux_serial_read(serial);	} else		serial->rx_state = RX_IDLE;}/* read callback for Diag and CS port */static void hso_std_serial_read_bulk_callback(CALLBACK_ARGS){	struct hso_serial *serial = urb->context;	int status = urb->status;	/* sanity check */	if (!serial) {		D1("serial == NULL");		return;	} else if (status) {		log_usb_status(status, __func__);		return;	}	D4("\n--- Got serial_read_bulk callback %02x ---", status);	D1("Actual length = %d\n", urb->actual_length);	DUMP1(urb->transfer_buffer, urb->actual_length);	/* Anyone listening? */	if (serial->open_count == 0)		return;	if (status == 0) {		if (serial->parent->port_spec & HSO_INFO_CRC_BUG) {			u32 rest;			u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };			rest =			    urb->actual_length %			    serial->in_endp->wMaxPacketSize;			if (((rest == 5) || (rest == 6))			    && !memcmp(((u8 *) urb->transfer_buffer) +				       urb->actual_length - 4, crc_check, 4)) {				urb->actual_length -= 4;			}		}		/* Valid data, handle RX data */		spin_lock(&serial->serial_lock);		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;		put_rxbuf_data_and_resubmit_bulk_urb(serial);		spin_unlock(&serial->serial_lock);	} else if (status == -ENOENT || status == -ECONNRESET) {		/* Unlinked - check for throttled port. */		D2("Port %d, successfully unlinked urb", serial->minor);		spin_lock(&serial->serial_lock);		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;		hso_resubmit_rx_bulk_urb(serial, urb);		spin_unlock(&serial->serial_lock);	} else {		D2("Port %d, status = %d for read urb", serial->minor, status);		return;	}}/* * This needs to be a tasklet otherwise we will * end up recursively calling this function. */void hso_unthrottle_tasklet(struct hso_serial *serial){	unsigned long flags;	spin_lock_irqsave(&serial->serial_lock, flags);	if ((serial->parent->port_spec & HSO_INTF_MUX))		put_rxbuf_data_and_resubmit_ctrl_urb(serial);	else		put_rxbuf_data_and_resubmit_bulk_urb(serial);	spin_unlock_irqrestore(&serial->serial_lock, flags);}static	void hso_unthrottle(struct tty_struct *tty){	struct hso_serial *serial = get_serial_by_tty(tty);	tasklet_hi_schedule(&serial->unthrottle_tasklet);}/* open the requested serial port */static int hso_serial_open(struct tty_struct *tty, struct file *filp){	struct hso_serial *serial = get_serial_by_index(tty->index);	int result1 = 0, result2 = 0;	struct MUTEX *hso_mutex = NULL;	int   released = 0;	/* sanity check */	if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {		tty->driver_data = NULL;		D1("Failed to open port");		return -ENODEV;	}	hso_mutex = &serial->parent->mutex->mutex;	mutex_lock(hso_mutex);	/* check for port already opened, if not set the termios */	/* The serial->open count needs to be here as hso_serial_close	 *  will be called even if hso_serial_open returns -ENODEV.	 */	serial->open_count++;#ifdef CONFIG_HSO_AUTOPM	result1 = usb_autopm_get_interface(serial->parent->interface);	if (result1 < 0)		goto err_out;#endif	D1("Opening %d", serial->minor);	kref_get(&serial->parent->ref);	/* setup */	tty->driver_data = serial;	serial->tty = tty;	if (serial->open_count == 1) {		tty->low_latency = 1;		serial->rx_state = RX_IDLE;		/* Force default termio settings */		_hso_serial_set_termios(tty, NULL);		tasklet_init(&serial->unthrottle_tasklet,			     (void (*)(unsigned long))hso_unthrottle_tasklet,			     (unsigned long)serial);		result2 = hso_start_serial_device(serial->parent, GFP_KERNEL);		if (result2) {			hso_stop_serial_device(serial->parent);			serial->open_count--;		}	} else {		D1("Port was already open");	}#ifdef CONFIG_HSO_AUTOPM	usb_autopm_put_interface(serial->parent->interface);#endif	/* done */	if (!result2)		hso_serial_tiocmset(tty, NULL, TIOCM_RTS | TIOCM_DTR, 0);#ifdef CONFIG_HSO_AUTOPMerr_out:#endif	if (result2)		released = hso_kref_put(&serial->parent->ref, hso_serial_ref_free);	mutex_unlock(hso_mutex);	if (released)		hso_free_mutex(container_of(hso_mutex,					    struct hso_mutex_t, mutex));	return result1 == 0 ? result2 : result1;}/* close the requested serial port */static void hso_serial_close(struct tty_struct *tty, struct file *filp){	struct hso_serial *serial = tty->driver_data;	u8 usb_gone;	struct MUTEX *hso_mutex;	int released;	D1("Closing serial port");	if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {		D1("invalid serial structure bailing out. ");		return;	}	hso_mutex = &serial->parent->mutex->mutex;	mutex_lock(hso_mutex);	usb_gone = serial->parent->usb_gone;#ifdef CONFIG_HSO_AUTOPM	if (!usb_gone)		usb_autopm_get_interface(serial->parent->interface);#endif	/* reset the rts and dtr */	/* do the actual close */	serial->open_count--;	if (serial->open_count <= 0) {		serial->open_count = 0;		if (serial->tty) {			serial->tty->driver_data = NULL;			serial->tty = NULL;		}		if (!usb_gone)			hso_stop_serial_device(serial->parent);		tasklet_kill(&serial->unthrottle_tasklet);	}#ifdef CONFIG_HSO_AUTOPM	if (!usb_gone)		usb_autopm_put_interface(serial->parent->interface);#endif	released = hso_kref_put(&serial->parent->ref, hso_serial_ref_free);	mutex_unlock(hso_mutex);	if (released)		hso_free_mutex(container_of(hso_mutex,					    struct hso_mutex_t, mutex));}/* close the requested serial port */static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,			    int count){	struct hso_serial *serial = get_serial_by_tty(tty);	int space, tx_bytes;	unsigned long flags;	/* sanity check */	if (serial == NULL) {		printk(KERN_ERR "%s: serial is NULL\n", __func__);		return -ENODEV;	}	spin_lock_irqsave(&serial->serial_lock, flags);	space = serial->tx_data_length - serial->tx_buffer_count;	tx_bytes = (count < space) ? count : space;	if (!tx_bytes)		goto out;	memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes);	serial->tx_buffer_count += tx_bytes;out:	spin_unlock_irqrestore(&serial->serial_lock, flags);	hso_kick_transmit(serial);	/* done */	return tx_bytes;}/* how much room is there for writing */static int hso_serial_write_room(struct tty_struct *tty){	struct hso_serial *serial = get_serial_by_tty(tty);	int room;	unsigned long flags;	spin_lock_irqsave(&serial->serial_lock, flags);	room = serial->tx_data_length - serial->tx_buffer_count;	spin_unlock_irqrestore(&serial->serial_lock, flags);	/* return free room */	return room;}/* setup the term */static void hso_serial_set_termios(struct tty_struct *tty, struct TERMIOS *old){	struct hso_serial *serial = get_serial_by_tty(tty);	unsigned long flags;	if (old)		D5("Termios called with: cflags new[%d] - old[%d]",		   tty->termios->c_cflag, old->c_cflag);	/* the actual setup */	spin_lock_irqsave(&serial->serial_lock, flags);	if (serial->open_count)		_hso_serial_set_termios(tty, old);	else		tty->termios = old;	spin_unlock_irqrestore(&serial->serial_lock, flags);	/* done */	return;}/* how many characters in the buffer */static int hso_serial_chars_in_buffer(struct tty_struct *tty){	struct hso_serial *serial = get_serial_by_tty(tty);	int chars;	unsigned long flags;	/* sanity check */	if (serial == NULL)		return 0;	spin_lock_irqsave(&serial->serial_lock, flags);	chars = serial->tx_buffer_count;	spin_unlock_irqrestore(&serial->serial_lock, flags);	return chars;}int tiocmget_submit_urb(struct hso_serial *serial,			struct hso_tiocmget  *tiocmget,			struct usb_device *usb){	int result;	if (serial->parent->usb_gone)		return -ENODEV;	usb_fill_int_urb(tiocmget->urb, usb,			 usb_rcvintpipe(usb,					tiocmget->endp->					bEndpointAddress & 0x7F),			 &tiocmget->serial_state_notification,			 sizeof(struct hso_serial_state_notification),			 tiocmget_intr_callback, serial,			 tiocmget->endp->bInterval);	result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);	if (result) {		dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,			 result);	}	return result;}static void tiocmget_intr_callback(CALLBACK_ARGS){	struct hso_serial *serial = urb->context;	struct hso_tiocmget *tiocmget;	int status = urb->status;	u16 UART_state_bitmap, prev_UART_state_bitmap;	struct uart_icount *icount;	struct hso_serial_state_notification *serial_state_notification;	struct usb_device *usb;	/* Sanity checks */	if (!serial)		return;	if (status) {		log_usb_status(status, __func__);		return;	}	tiocmget = serial->tiocmget;	if (!tiocmget)		return;	usb = serial->parent->usb;	serial_state_notification = &tiocmget->serial_state_notification;	if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||	    serial_state_notification->bNotification != B_NOTIFICATION ||	    le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||	    le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||	    le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {		dev_warn(&usb->dev,			 "hso received invalid serial state notification\n");		DUMP((unsigned char *)serial_state_notification,		     sizeof(struct hso_serial_state_notification));	} else {		UART_state_bitmap = le16_to_cpu(serial_state_notification->						UART_state_bitmap);		prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;		icount = &tiocmget->icount;		spin_lock(&serial->serial_lock);		if ((UART_state_bitmap & B_OVERRUN) !=		   (prev_UART_state_bitmap & B_OVERRUN))			icount->parity++;		if ((UART_state_bitmap & B_PARITY) !=		   (prev_UART_state_bitmap & B_PARITY))			icount->parity++;		if ((UART_state_bitmap & B_FRAMING) !=		   (prev_UART_state_bitmap & B_FRAMING))			icount->frame++;		if ((UART_state_bitmap & B_RING_SIGNAL) &&		   !(prev_UART_state_bitmap & B_RING_SIGNAL))			icount->rng++;		if ((UART_state_bitmap & B_BREAK) !=		   (prev_UART_state_bitmap & B_BREAK))			icount->brk++;		if ((UART_state_bitmap & B_TX_CARRIER) !=		   (prev_UART_state_bitmap & B_TX_CARRIER))			icount->dsr++;		if ((UART_state_bitmap & B_RX_CARRIER) !=		   (prev_UART_state_bitmap & B_RX_CARRIER))			icount->dcd++;		tiocmget->prev_UART_state_bitmap = UART_state_bitmap;		spin_unlock(&serial->serial_lock);		tiocmget->intr_completed = 1;		wake_up_interruptible(&tiocmget->waitq);	}	memset(serial_state_notification, 0,	       sizeof(struct hso_serial_state_notification));	tiocmget_submit_urb(serial,			    tiocmget,			    serial->parent->usb);}/* * next few functions largely stolen from drivers/serial/serial_core.c *//* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */static inthso_wait_modem_status(struct hso_serial *serial, unsigned long arg){	DECLARE_WAITQUEUE(wait, current);	struct uart_icount cprev, cnow;	struct hso_tiocmget  *tiocmget;	int ret;	tiocmget = serial->tiocmget;	if (!tiocmget)		return -ENOENT;	/*	 * note the counters on entry	 */	spin_lock_irq(&serial->serial_lock);	memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));	spin_unlock_irq(&serial->serial_lock);	add_wait_queue(&tiocmget->waitq, &wait);	for (;;) {		spin_lock_irq(&serial->serial_lock);		memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));		spin_unlock_irq(&serial->serial_lock);		set_current_state(TASK_INTERRUPTIBLE);		if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||		    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||		    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd))) {			ret = 0;			break;		}		schedule();		/* see if a signal did it */		if (signal_pending(current)) {			ret = -ERESTARTSYS;			break;		}		cprev = cnow;	}	current->state = TASK_RUNNING;	remove_wait_queue(&tiocmget->waitq, &wait);	return ret;}/* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for *     RI where only 0->1 is counted. */static int hso_get_count(struct hso_serial *serial,			  struct serial_icounter_struct __user *icnt){	struct serial_icounter_struct icount;	struct uart_icount cnow;	struct hso_tiocmget  *tiocmget = serial->tiocmget;	if (!tiocmget)		 return -ENOENT;	spin_lock_irq(&serial->serial_lock);	memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));	spin_unlock_irq(&serial->serial_lock);	icount.cts         = cnow.cts;	icount.dsr         = cnow.dsr;	icount.rng         = cnow.rng;	icount.dcd         = cnow.dcd;	icount.rx          = cnow.rx;	icount.tx          = cnow.tx;	icount.frame       = cnow.frame;	icount.overrun     = cnow.overrun;	icount.parity      = cnow.parity;	icount.brk         = cnow.brk;	icount.buf_overrun = cnow.buf_overrun;	return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;}

⌨️ 快捷键说明

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