static void qt_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct quatech_port *qt_port; struct quatech_port *port0; struct tty_struct *tty; int status; unsigned int index; status = 0; tty = tty_port_tty_get(&port->port); index = tty->index - serial->minor; qt_port = qt_get_port_private(port); port0 = qt_get_port_private(serial->port[0]); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) usb_unlink_urb(port->write_urb); if (serial->num_bulk_in) usb_unlink_urb(port->read_urb); /* wait up to for transmitter to empty */ if (serial->dev) qt_block_until_empty(tty, qt_port); tty_kref_put(tty); /* Close uart channel */ status = qt_close_channel(serial, index); if (status < 0) dev_dbg(&port->dev, "%s - port %d qt_close_channel failed.\n", __func__, port->number); port0->open_ports--; dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n", port0->open_ports, port->number); if (port0->open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n"); usb_kill_urb(serial->port[0]->interrupt_in_urb); } } if (qt_port->write_urb) { /* if this urb had a transfer buffer already (old tx) free it */ kfree(qt_port->write_urb->transfer_buffer); usb_free_urb(qt_port->write_urb); } }
static void qt_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port; if (!serial) return; qt_port = qt_get_port_private(port); mutex_lock(&qt_port->lock); if (qt_port->RxHolding == 1) { dev_dbg(&port->dev, "%s -qt_port->RxHolding == 1\n", __func__); qt_port->RxHolding = 0; dev_dbg(&port->dev, "%s - qt_port->RxHolding = 0\n", __func__); /* if we have a bulk endpoint, start it up */ if ((serial->num_bulk_in) && (qt_port->ReadBulkStopped == 1)) qt_submit_urb_from_unthrottle(port, serial); } mutex_unlock(&qt_port->lock); }
static void qt_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port; u16 index, onoff; unsigned int result; index = tty->index - serial->minor; qt_port = qt_get_port_private(port); if (break_state == -1) onoff = 1; else onoff = 0; mutex_lock(&qt_port->lock); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300); mutex_unlock(&qt_port->lock); }
static int qt_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial; struct quatech_port *qt_port; int retval = -EINVAL; if (port_paranoia_check(port, __func__)) return -1; serial = get_usb_serial(port, __func__); if (!serial) return -ENODEV; qt_port = qt_get_port_private(port); mutex_lock(&qt_port->lock); if (serial->num_bulk_out) { if (port->write_urb->status != -EINPROGRESS) retval = port->bulk_out_size; } mutex_unlock(&qt_port->lock); return retval; }
static int qt_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port = qt_get_port_private(port); int retval; if (!serial) return -ENODEV; mutex_lock(&qt_port->lock); retval = qt_real_tiocmget(tty, port, serial); mutex_unlock(&qt_port->lock); return retval; }
static int qt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct quatech_port *qt_port = qt_get_port_private(port); unsigned int index; dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); index = port->port_number; if (cmd == TIOCMIWAIT) { while (qt_port != NULL) { #if 0 /* this never wakes up */ interruptible_sleep_on(&qt_port->msr_wait); #endif if (signal_pending(current)) return -ERESTARTSYS; else { char diff = qt_port->diff_status; if (diff == 0) return -EIO; /* no change => error */ /* Consume all events */ qt_port->diff_status = 0; if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) || ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) || ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) || ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS))) { return 0; } } } return 0; } dev_dbg(&port->dev, "%s -No ioctl for that one.\n", __func__); return -ENOIOCTLCMD; }
static void qt_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port; if (!serial) return; qt_port = qt_get_port_private(port); mutex_lock(&qt_port->lock); /* pass on to the driver specific version of this function */ qt_port->RxHolding = 1; mutex_unlock(&qt_port->lock); }
static int qt_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial; struct quatech_port *quatech_port; struct quatech_port *port0; struct qt_open_channel_data ChannelData; int result; if (port_paranoia_check(port, __func__)) return -ENODEV; serial = port->serial; if (serial_paranoia_check(serial, __func__)) return -ENODEV; quatech_port = qt_get_port_private(port); port0 = qt_get_port_private(serial->port[0]); if (quatech_port == NULL || port0 == NULL) return -ENODEV; usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); port0->open_ports++; result = qt_get_device(serial, &port0->DeviceData); /* Port specific setups */ result = qt_open_channel(serial, port->number, &ChannelData); if (result < 0) { dev_dbg(&port->dev, "qt_open_channel failed\n"); return result; } dev_dbg(&port->dev, "qt_open_channel completed.\n"); /* FIXME: are these needed? Does it even do anything useful? */ quatech_port->shadowLSR = ChannelData.line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); quatech_port->shadowMSR = ChannelData.modem_status & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); /* Set Baud rate to default and turn off (default)flow control here */ result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR); if (result < 0) { dev_dbg(&port->dev, "qt_setuart failed\n"); return result; } dev_dbg(&port->dev, "qt_setuart completed.\n"); /* * Put this here to make it responsive to stty and defaults set by * the tty layer */ /* Check to see if we've set up our endpoint info yet */ if (port0->open_ports == 1) { if (serial->port[0]->interrupt_in_buffer == NULL) qt_submit_urb_from_open(serial, port); } dev_dbg(&port->dev, "port number is %d\n", port->number); dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor); dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress); dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress); dev_dbg(&port->dev, "port's number in the device is %d\n", quatech_port->port_num); quatech_port->read_urb = port->read_urb; /* set up our bulk in urb */ usb_fill_bulk_urb(quatech_port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->bulk_in_buffer, quatech_port->read_urb->transfer_buffer_length, qt_read_bulk_callback, quatech_port); dev_dbg(&port->dev, "qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress); quatech_port->read_urb_busy = true; result = usb_submit_urb(quatech_port->read_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - Error %d submitting control urb\n", __func__, result); quatech_port->read_urb_busy = false; } /* initialize our wait queues */ init_waitqueue_head(&quatech_port->wait); init_waitqueue_head(&quatech_port->msr_wait); /* initialize our icount structure */ memset(&(quatech_port->icount), 0x00, sizeof(quatech_port->icount)); return 0; }
static int qt_startup(struct usb_serial *serial) { struct device *dev = &serial->dev->dev; struct usb_serial_port *port; struct quatech_port *qt_port; struct qt_get_device_data DeviceData; int i; int status; /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL); if (!qt_port) { for (--i; i >= 0; i--) { port = serial->port[i]; kfree(usb_get_serial_port_data(port)); usb_set_serial_port_data(port, NULL); } return -ENOMEM; } mutex_init(&qt_port->lock); usb_set_serial_port_data(port, qt_port); } status = qt_get_device(serial, &DeviceData); if (status < 0) goto startup_error; dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb); DeviceData.portb &= ~FULLPWRBIT; dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb); status = qt_set_device(serial, &DeviceData); if (status < 0) { dev_dbg(dev, "qt_set_device failed\n"); goto startup_error; } status = qt_get_device(serial, &DeviceData); if (status < 0) { dev_dbg(dev, "qt_get_device failed\n"); goto startup_error; } switch (serial->dev->descriptor.idProduct) { case QUATECH_DSU100: case QUATECH_QSU100: case QUATECH_ESU100A: case QUATECH_ESU100B: case QUATECH_HSU100A: case QUATECH_HSU100B: case QUATECH_HSU100C: case QUATECH_HSU100D: DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); DeviceData.porta |= CLKS_X4; DeviceData.portb &= ~(LOOPMODE_BITS); DeviceData.portb |= RS232_MODE; break; case QUATECH_SSU200: case QUATECH_DSU200: case QUATECH_QSU200: case QUATECH_ESU200A: case QUATECH_ESU200B: case QUATECH_HSU200A: case QUATECH_HSU200B: case QUATECH_HSU200C: case QUATECH_HSU200D: DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); DeviceData.porta |= CLKS_X4; DeviceData.portb &= ~(LOOPMODE_BITS); DeviceData.portb |= ALL_LOOPBACK; break; default: DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); DeviceData.porta |= CLKS_X4; DeviceData.portb &= ~(LOOPMODE_BITS); DeviceData.portb |= RS232_MODE; break; } status = BoxSetPrebufferLevel(serial); /* sets to default value */ if (status < 0) { dev_dbg(dev, "BoxSetPrebufferLevel failed\n"); goto startup_error; } status = BoxSetATC(serial, ATC_DISABLED); if (status < 0) { dev_dbg(dev, "BoxSetATC failed\n"); goto startup_error; } dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb); DeviceData.portb |= NEXT_BOARD_POWER_BIT; dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb); status = qt_set_device(serial, &DeviceData); if (status < 0) { dev_dbg(dev, "qt_set_device failed\n"); goto startup_error; } return 0; startup_error: for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; qt_port = qt_get_port_private(port); kfree(qt_port); usb_set_serial_port_data(port, NULL); } return -EIO; }
static void qt_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port = qt_get_port_private(port); int result; if (urb->status) { qt_port->ReadBulkStopped = 1; dev_dbg(&urb->dev->dev, "%s - nonzero write bulk status received: %d\n", __func__, urb->status); return; } dev_dbg(&port->dev, "%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); if (port_paranoia_check(port, __func__) != 0) { qt_port->ReadBulkStopped = 1; return; } if (!serial) return; if (qt_port->closePending == 1) { /* Were closing , stop reading */ dev_dbg(&port->dev, "%s - (qt_port->closepending == 1\n", __func__); qt_port->ReadBulkStopped = 1; return; } /* * RxHolding is asserted by throttle, if we assert it, we're not * receiving any more characters and let the box handle the flow * control */ if (qt_port->RxHolding == 1) { qt_port->ReadBulkStopped = 1; return; } if (urb->status) { qt_port->ReadBulkStopped = 1; dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n", __func__, urb->status); return; } if (urb->actual_length) qt_status_change_check(urb, qt_port, port); /* Continue trying to always read */ usb_fill_bulk_urb(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, qt_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) dev_dbg(&port->dev, "%s - failed resubmitting read urb, error %d", __func__, result); else { if (urb->actual_length) { tty_flip_buffer_push(&port->port); tty_schedule_flip(&port->port); } } schedule_work(&port->work); }