📄 usbdev.c
字号:
send_packet_complete(ep); // mark a bh to wakeup any tty write system call on the port. queue_task(&port->send_complete_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } spin_unlock(&ep->lock); /* * Now check packet receive done (bulk OUT ep). Shouldn't * get these, the receive packet complete intr should happen * before the DMA done intr occurs. */ ep = &port->ep_bulkout; spin_lock(&ep->lock); if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) { // received a DATAx packet on the port's bulk OUT endpoint // clear DMA done bit if (buff_done == DMA_D0) clear_dma_done0(ep->outdma); else clear_dma_done1(ep->outdma); } spin_unlock(&ep->lock);}// This ISR needs to handle dma done events for ALL endpoints!static voiddma_done_intr (int irq, void *dev_id, struct pt_regs *regs){ struct usb_serial *serial = (struct usb_serial *) dev_id; int i; dma_done_ctrl(serial); for (i = 0; i < NUM_PORTS; i++) dma_done_port(&serial->port[i]);}/***************************************************************************** * Here begins the tty driver interface functions *****************************************************************************/static int serial_open(struct tty_struct *tty, struct file *filp){ int portNumber; struct usb_serial_port *port; struct usb_serial *serial = &usbserial; unsigned long flags; /* initialize the pointer incase something fails */ tty->driver_data = NULL; MOD_INC_USE_COUNT; /* set up our port structure making the tty driver remember our port object, and us it */ portNumber = MINOR(tty->device) - serial->minor; port = &serial->port[portNumber]; tty->driver_data = port; port->tty = tty; if (port_paranoia_check(port, __FUNCTION__)) return -ENODEV; dbg(__FUNCTION__ " - port %d", port->number); spin_lock_irqsave(&port->port_lock, flags); ++port->open_count; if (!port->active) { port->active = 1; /* * 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. */ port->tty->low_latency = 1; } spin_unlock_irqrestore(&port->port_lock, flags); return 0;}static void serial_close(struct tty_struct *tty, struct file *filp){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); unsigned long flags; if (!serial) return; dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { dbg(__FUNCTION__ " - port not opened"); return; } spin_lock_irqsave(&port->port_lock, flags); --port->open_count; if (port->open_count <= 0) { port->active = 0; port->open_count = 0; } spin_unlock_irqrestore(&port->port_lock, flags); MOD_DEC_USE_COUNT;}static int serial_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); endpoint_t *ep = &port->ep_bulkin; if (!serial) return -ENODEV; if (!port->active) { dbg(__FUNCTION__ " - port not opened"); return -EINVAL; } if (count == 0) { dbg(__FUNCTION__ " - write request of 0 bytes"); return (0); } count = (count > ep->max_pkt_size) ? ep->max_pkt_size : count; send_packet(ep, (u8 *) buf, count, from_user); return (count);}static int serial_write_room(struct tty_struct *tty){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); endpoint_t *ep = &port->ep_bulkin; if (!serial) return -ENODEV; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return -EINVAL; } return ep->max_pkt_size;}static int serial_chars_in_buffer(struct tty_struct *tty){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); endpoint_t *ep = &port->ep_bulkin; pkt_list_t *list = &ep->inlist; pkt_t *scan; unsigned long flags; int chars = 0; if (!serial) return -ENODEV; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return -EINVAL; } spin_lock_irqsave(&ep->lock, flags); for (scan = list->head; scan; scan = scan->next) chars += scan->size; spin_unlock_irqrestore(&ep->lock, flags); return (chars);}static void serial_throttle(struct tty_struct *tty){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); if (!serial) return; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return; } // FIXME: anything to do?}static void serial_unthrottle(struct tty_struct *tty){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); if (!serial) return; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return; } // FIXME: anything to do?}static int serial_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); if (!serial) return -ENODEV; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return -ENODEV; } // FIXME: need any IOCTLs? return -ENOIOCTLCMD;}static void serial_set_termios(struct tty_struct *tty, struct termios *old){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); if (!serial) return; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return; } // FIXME: anything to do?}static void serial_break(struct tty_struct *tty, int break_state){ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); if (!serial) return; if (!port->active) { dbg(__FUNCTION__ " - port not open"); return; } // FIXME: anything to do?}static void port_send_complete(void *private){ struct usb_serial_port *port = (struct usb_serial_port *) private; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); struct tty_struct *tty; dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { return; } tty = port->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { dbg(__FUNCTION__ " - write wakeup call."); (tty->ldisc.write_wakeup) (tty); } wake_up_interruptible(&tty->write_wait);}static void port_receive_complete(void *private){ struct usb_serial_port *port = (struct usb_serial_port *) private; struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); struct tty_struct *tty = port->tty; pkt_t *pkt; int i; dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { return; } if (!(pkt = receive_packet(&port->ep_bulkout))) return; for (i = 0; i < pkt->size; i++) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } /* this doesn't actually push the data through unless tty->low_latency is set */ tty_insert_flip_char(tty, pkt->bufptr[i], 0); } tty_flip_buffer_push(tty); // we're done processing the packet, free it kfree(pkt);}static struct tty_driver serial_tty_driver = { magic:TTY_DRIVER_MAGIC, driver_name:"usbdev-serial", name:"usb/ttsdev/%d", major:SERIAL_TTY_MAJOR, minor_start:0, num:1, type:TTY_DRIVER_TYPE_SERIAL, subtype:SERIAL_TYPE_NORMAL, flags:TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, refcount:&serial_refcount, table:serial_tty, termios:serial_termios, termios_locked:serial_termios_locked, open:serial_open, close:serial_close, write:serial_write, write_room:serial_write_room, ioctl:serial_ioctl, set_termios:serial_set_termios, throttle:serial_throttle, unthrottle:serial_unthrottle, break_ctl:serial_break, chars_in_buffer:serial_chars_in_buffer,};void usbdev_serial_exit(void){ endpoint_t *ep; int i; outl_sync(0, USB_DEV_INT_ENABLE); // disable usb dev ints outl_sync(0, USB_DEV_ENABLE); // disable usb dev // first free all control endpoint resources ep = &usbserial.ep_ctrl; free_irq(AU1000_USB_DEV_REQ_INT, &usbserial); free_irq(AU1000_USB_DEV_SUS_INT, &usbserial); free_irq(ep->inirq, &usbserial); //free_irq(ep->outirq, &usbserial); free_au1000_dma(ep->indma); free_au1000_dma(ep->outdma); endpoint_flush(ep); // now free all port resources for (i = 0; i < NUM_PORTS; i++) { // free port's bulk IN endpoint resources ep = &usbserial.port[i].ep_bulkin; free_irq(ep->inirq, &usbserial); free_au1000_dma(ep->indma); endpoint_flush(ep); // free port's bulk OUT endpoint resources ep = &usbserial.port[i].ep_bulkout; //free_irq(ep->outirq, &usbserial); free_au1000_dma(ep->outdma); endpoint_flush(ep); tty_unregister_devfs(&serial_tty_driver, i); info("usbdev serial converter now disconnected from ttyUSBdev%d", i); } kfree(usbserial.str_desc[0]); tty_unregister_driver(&serial_tty_driver);}int usbdev_serial_init(void){ struct usb_serial_port *port; endpoint_t *ep; void *str_desc_buf; int str_desc_len; int i; /* register the tty driver */ serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; if (tty_register_driver(&serial_tty_driver)) { err(__FUNCTION__ ": failed to register tty driver"); return -1; } memset(&usbserial, 0, sizeof(struct usb_serial)); usbserial.minor = 0; usbserial.state = DEFAULT; usbserial.dev_desc = &dev_desc; usbserial.if_desc = &if_desc; usbserial.conf_desc = &config_desc; /* * initialize the string descriptors */ /* alloc buffer big enough for all string descriptors */ str_desc_len = string_desc0.bLength; for (i = 0; i < 5; i++) str_desc_len += 2 + 2 * strlen(strings[i]); str_desc_buf = (void *) kmalloc(str_desc_len, ALLOC_FLAGS); if (!str_desc_buf) { err(__FUNCTION__ ": failed to alloc string descriptors"); return -1; } usbserial.str_desc[0] = (struct usb_string_descriptor *)str_desc_buf; memcpy(usbserial.str_desc[0], &string_desc0, string_desc0.bLength); usbserial.str_desc[1] = (struct usb_string_descriptor *) (str_desc_buf + string_desc0.bLength); for (i = 1; i < 6; i++) { struct usb_string_descriptor *desc = usbserial.str_desc[i]; char *str = strings[i - 1]; int j, str_len = strlen(str); desc->bLength = 2 + 2 * str_len; desc->bDescriptorType = USB_DT_STRING; for (j = 0; j < str_len; j++) { desc->wData[j] = (u16) str[j]; } if (i < 5) usbserial.str_desc[i + 1] = (struct usb_string_descriptor *) ((u8 *) desc + desc->bLength); } // request the USB device transfer complete interrupt if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_SHIRQ, "USBdev req", &usbserial)) { err("Can't get device request intr\n"); goto err_out; } // request the USB device suspend interrupt if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_SHIRQ, "USBdev sus", &usbserial)) { err("Can't get device suspend intr\n"); goto err_out; } // Initialize default control endpoint ep = &usbserial.ep_ctrl; spin_lock_init(&ep->lock); ep->desc = NULL; // ep0 has no ep descriptor ep->reg = &ep_reg[0]; ep->max_pkt_size = usbserial.dev_desc->bMaxPacketSize0; ep->indma = ep->outdma = -1; if ((ep->indma = request_au1000_dma(ep_dma_id[0].id, ep_dma_id[0].str)) < 0) { err("Can't get %s DMA\n", ep_dma_id[0].str); goto err_out; } if ((ep->outdma = request_au1000_dma(ep_dma_id[1].id, ep_dma_id[1].str)) < 0) { err("Can't get %s DMA\n", ep_dma_id[1].str); goto err_out; } ep->inirq = get_dma_done_irq(ep->indma); ep->outirq = get_dma_done_irq(ep->outdma); // allocate EP0's DMA done interrupts. if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT, "USBdev ep0 IN", &usbserial)) { err("Can't get ep0 IN dma done irq\n"); goto err_out; }#if 0 if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT, "USBdev ep0 OUT", &usbserial)) { err("Can't get ep0 OUT dma done irq\n"); goto err_out; }#endif /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ for (i = 0; i < NUM_PORTS; ++i) { tty_register_devfs(&serial_tty_driver, 0, i); info("usbdev serial attached to ttyUSBdev%d (or devfs usb/ttsdev/%d)", i, i); port = &usbserial.port[i]; port->serial = &usbserial; port->number = i; port->send_complete_tq.routine = port_send_complete; port->send_complete_tq.data = port; port->receive_complete_tq.routine = port_receive_complete; port->receive_complete_tq.data = port; spin_lock_init(&port->port_lock); // Initialize the port's bulk IN endpoint ep = &port->ep_bulkin; spin_lock_init(&ep->lock); ep->desc = &ep_desc[NUM_PORTS * i]; ep->reg = &ep_reg[1 + NUM_PORTS * i]; ep->max_pkt_size = ep->desc->wMaxPacketSize; ep->indma = ep->outdma = -1; if ((ep->indma = request_au1000_dma(ep_dma_id[2+NUM_PORTS*i].id, ep_dma_id[2 + NUM_PORTS * i].str)) < 0) { err("Can't get %s DMA\n", ep_dma_id[2 + NUM_PORTS * i].str); goto err_out; } ep->inirq = get_dma_done_irq(ep->indma); if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT, "USBdev bulk IN", &usbserial)) { err("Can't get port %d bulk IN dma done irq\n", i); goto err_out; } // Initialize the port's bulk OUT endpoint ep = &port->ep_bulkout; spin_lock_init(&ep->lock); ep->desc = &ep_desc[NUM_PORTS * i + 1]; ep->reg = &ep_reg[1 + NUM_PORTS * i + 1]; ep->max_pkt_size = ep->desc->wMaxPacketSize; ep->indma = ep->outdma = -1; if ((ep->outdma = request_au1000_dma(ep_dma_id[2+NUM_PORTS*i + 1].id, ep_dma_id[2+NUM_PORTS*i + 1].str)) < 0) { err("Can't get %s DMA\n", ep_dma_id[2 + NUM_PORTS * i + 1].str); goto err_out; } ep->outirq = get_dma_done_irq(ep->outdma);#if 0 if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT, "USBdev bulk OUT", &usbserial)) { err("Can't get port %d bulk OUT dma done irq\n", i); goto err_out; }#endif } // enable device controller outl_sync(0x0002, USB_DEV_ENABLE); udelay(100); outl_sync(0x0003, USB_DEV_ENABLE); udelay(100); for (i = 0; i < sizeof(au1000_config_table) / sizeof(u32); ++i) outl_sync(au1000_config_table[i], USB_DEV_CONFIG); // Flush the endpoint buffers and FIFOs ep = &usbserial.ep_ctrl; endpoint_flush(ep); // start packet reception on control ep kickstart_receive_packet(ep); for (i = 0; i < NUM_PORTS; ++i) { struct usb_serial_port *port = &usbserial.port[i]; endpoint_flush(&port->ep_bulkin); endpoint_flush(&port->ep_bulkout); // start packet reception on bulk OUT endpoint kickstart_receive_packet(&port->ep_bulkout); } /* * Enable Receive FIFO Complete interrupts only. Transmit * complete is being handled by the DMA done interrupts. */ outl_sync(0x31, USB_DEV_INT_ENABLE); return 0; err_out: usbdev_serial_exit(); return -1;}module_init(usbdev_serial_init);module_exit(usbdev_serial_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -