?? hso.c
字號:
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 + -