1 |
1275 |
phoenix |
/*
|
2 |
|
|
* BRIEF MODULE DESCRIPTION
|
3 |
|
|
* Au1x00 USB Device-Side Serial TTY Driver (function layer)
|
4 |
|
|
*
|
5 |
|
|
* Copyright 2001-2002 MontaVista Software Inc.
|
6 |
|
|
* Author: MontaVista Software, Inc.
|
7 |
|
|
* stevel@mvista.com or source@mvista.com
|
8 |
|
|
*
|
9 |
|
|
* Derived from drivers/usb/serial/usbserial.c:
|
10 |
|
|
*
|
11 |
|
|
* Copyright (C) 1999 - 2001 Greg Kroah-Hartman (greg@kroah.com)
|
12 |
|
|
* Copyright (c) 2000 Peter Berger (pberger@brimson.com)
|
13 |
|
|
* Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
|
14 |
|
|
*
|
15 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
16 |
|
|
* under the terms of the GNU General Public License as published by the
|
17 |
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
18 |
|
|
* option) any later version.
|
19 |
|
|
*
|
20 |
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
21 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
22 |
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
23 |
|
|
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
24 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
25 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
26 |
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
27 |
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
28 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
29 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30 |
|
|
*
|
31 |
|
|
* You should have received a copy of the GNU General Public License along
|
32 |
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
33 |
|
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
34 |
|
|
*/
|
35 |
|
|
|
36 |
|
|
#include <linux/config.h>
|
37 |
|
|
#include <linux/kernel.h>
|
38 |
|
|
#include <linux/ioport.h>
|
39 |
|
|
#include <linux/sched.h>
|
40 |
|
|
#include <linux/signal.h>
|
41 |
|
|
#include <linux/errno.h>
|
42 |
|
|
#include <linux/poll.h>
|
43 |
|
|
#include <linux/init.h>
|
44 |
|
|
#include <linux/slab.h>
|
45 |
|
|
#include <linux/fcntl.h>
|
46 |
|
|
#include <linux/tty.h>
|
47 |
|
|
#include <linux/tty_driver.h>
|
48 |
|
|
#include <linux/tty_flip.h>
|
49 |
|
|
#include <linux/module.h>
|
50 |
|
|
#include <linux/spinlock.h>
|
51 |
|
|
#include <linux/list.h>
|
52 |
|
|
#include <linux/smp_lock.h>
|
53 |
|
|
#undef DEBUG
|
54 |
|
|
#include <linux/usb.h>
|
55 |
|
|
|
56 |
|
|
#include <asm/io.h>
|
57 |
|
|
#include <asm/uaccess.h>
|
58 |
|
|
#include <asm/irq.h>
|
59 |
|
|
#include <asm/au1000.h>
|
60 |
|
|
#include <asm/au1000_usbdev.h>
|
61 |
|
|
|
62 |
|
|
|
63 |
|
|
/* local function prototypes */
|
64 |
|
|
static int serial_open(struct tty_struct *tty, struct file *filp);
|
65 |
|
|
static void serial_close(struct tty_struct *tty, struct file *filp);
|
66 |
|
|
static int serial_write(struct tty_struct *tty, int from_user,
|
67 |
|
|
const unsigned char *buf, int count);
|
68 |
|
|
static int serial_write_room(struct tty_struct *tty);
|
69 |
|
|
static int serial_chars_in_buffer(struct tty_struct *tty);
|
70 |
|
|
static void serial_throttle(struct tty_struct *tty);
|
71 |
|
|
static void serial_unthrottle(struct tty_struct *tty);
|
72 |
|
|
static int serial_ioctl(struct tty_struct *tty, struct file *file,
|
73 |
|
|
unsigned int cmd, unsigned long arg);
|
74 |
|
|
static void serial_set_termios (struct tty_struct *tty, struct termios * old);
|
75 |
|
|
|
76 |
|
|
#define SERIAL_TTY_MAJOR 189 // FIXME: need a legal major
|
77 |
|
|
|
78 |
|
|
#define MAX_NUM_PORTS 2
|
79 |
|
|
|
80 |
|
|
#define IN_MAX_PACKET_SIZE 32
|
81 |
|
|
#define OUT_MAX_PACKET_SIZE 32
|
82 |
|
|
|
83 |
|
|
// FIXME: when Au1x00 endpoints 3 and 5 are fixed, make NUM_PORTS=2
|
84 |
|
|
#define NUM_PORTS 2
|
85 |
|
|
#define NUM_EP 2*NUM_PORTS
|
86 |
|
|
|
87 |
|
|
#define CONFIG_DESC_LEN \
|
88 |
|
|
USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZE
|
89 |
|
|
|
90 |
|
|
struct usb_serial_port {
|
91 |
|
|
struct tty_struct *tty; /* the coresponding tty for this port */
|
92 |
|
|
unsigned char number;
|
93 |
|
|
spinlock_t port_lock;
|
94 |
|
|
|
95 |
|
|
struct usb_endpoint_descriptor* out_desc;
|
96 |
|
|
struct usb_endpoint_descriptor* in_desc;
|
97 |
|
|
|
98 |
|
|
int out_ep_addr; /* endpoint address of OUT endpoint */
|
99 |
|
|
int in_ep_addr; /* endpoint address of IN endpoint */
|
100 |
|
|
|
101 |
|
|
/* task queue for line discipline waking up on send packet complete */
|
102 |
|
|
struct tq_struct send_complete_tq;
|
103 |
|
|
/* task queue for line discipline wakeup on receive packet complete */
|
104 |
|
|
struct tq_struct receive_complete_tq;
|
105 |
|
|
|
106 |
|
|
int active; /* someone has this device open */
|
107 |
|
|
int writing; /* a packet write is in progress */
|
108 |
|
|
int open_count; /* number of times this port has been opened */
|
109 |
|
|
|
110 |
|
|
};
|
111 |
|
|
|
112 |
|
|
static struct usb_serial {
|
113 |
|
|
usbdev_state_t dev_state; // current state of device layer
|
114 |
|
|
struct usb_device_descriptor* dev_desc;
|
115 |
|
|
struct usb_config_descriptor* config_desc;
|
116 |
|
|
struct usb_interface_descriptor* if_desc;
|
117 |
|
|
struct usb_string_descriptor * str_desc[6];
|
118 |
|
|
void* str_desc_buf;
|
119 |
|
|
|
120 |
|
|
struct usb_serial_port port[NUM_PORTS];
|
121 |
|
|
} usbtty;
|
122 |
|
|
|
123 |
|
|
static int serial_refcount;
|
124 |
|
|
static struct tty_driver serial_tty_driver;
|
125 |
|
|
static struct tty_struct * serial_tty[NUM_PORTS];
|
126 |
|
|
static struct termios * serial_termios[NUM_PORTS];
|
127 |
|
|
static struct termios * serial_termios_locked[NUM_PORTS];
|
128 |
|
|
|
129 |
|
|
static struct usb_device_descriptor dev_desc = {
|
130 |
|
|
bLength:USB_DT_DEVICE_SIZE,
|
131 |
|
|
bDescriptorType:USB_DT_DEVICE,
|
132 |
|
|
bcdUSB:USBDEV_REV, //usb rev
|
133 |
|
|
bDeviceClass:USB_CLASS_PER_INTERFACE, //class (none)
|
134 |
|
|
bDeviceSubClass:0x00, //subclass (none)
|
135 |
|
|
bDeviceProtocol:0x00, //protocol (none)
|
136 |
|
|
bMaxPacketSize0:USBDEV_EP0_MAX_PACKET_SIZE, //max packet size for ep0
|
137 |
|
|
idVendor:0x6d04, //vendor id
|
138 |
|
|
idProduct:0x0bc0, //product id
|
139 |
|
|
bcdDevice:0x0001, //BCD rev 0.1
|
140 |
|
|
iManufacturer:0x01, //manufactuer string index
|
141 |
|
|
iProduct:0x02, //product string index
|
142 |
|
|
iSerialNumber:0x03, //serial# string index
|
143 |
|
|
bNumConfigurations:0x01 //num configurations
|
144 |
|
|
};
|
145 |
|
|
|
146 |
|
|
static struct usb_endpoint_descriptor ep_desc[] = {
|
147 |
|
|
{
|
148 |
|
|
// Bulk IN for Port 0
|
149 |
|
|
bLength:USB_DT_ENDPOINT_SIZE,
|
150 |
|
|
bDescriptorType:USB_DT_ENDPOINT,
|
151 |
|
|
bEndpointAddress:USB_DIR_IN,
|
152 |
|
|
bmAttributes:USB_ENDPOINT_XFER_BULK,
|
153 |
|
|
wMaxPacketSize:IN_MAX_PACKET_SIZE,
|
154 |
|
|
bInterval:0x00 // ignored for bulk
|
155 |
|
|
},
|
156 |
|
|
{
|
157 |
|
|
// Bulk OUT for Port 0
|
158 |
|
|
bLength:USB_DT_ENDPOINT_SIZE,
|
159 |
|
|
bDescriptorType:USB_DT_ENDPOINT,
|
160 |
|
|
bEndpointAddress:USB_DIR_OUT,
|
161 |
|
|
bmAttributes:USB_ENDPOINT_XFER_BULK,
|
162 |
|
|
wMaxPacketSize:OUT_MAX_PACKET_SIZE,
|
163 |
|
|
bInterval:0x00 // ignored for bulk
|
164 |
|
|
},
|
165 |
|
|
{
|
166 |
|
|
// Bulk IN for Port 1
|
167 |
|
|
bLength:USB_DT_ENDPOINT_SIZE,
|
168 |
|
|
bDescriptorType:USB_DT_ENDPOINT,
|
169 |
|
|
bEndpointAddress:USB_DIR_IN,
|
170 |
|
|
bmAttributes:USB_ENDPOINT_XFER_BULK,
|
171 |
|
|
wMaxPacketSize:IN_MAX_PACKET_SIZE,
|
172 |
|
|
bInterval:0x00 // ignored for bulk
|
173 |
|
|
},
|
174 |
|
|
{
|
175 |
|
|
// Bulk OUT for Port 1
|
176 |
|
|
bLength:USB_DT_ENDPOINT_SIZE,
|
177 |
|
|
bDescriptorType:USB_DT_ENDPOINT,
|
178 |
|
|
bEndpointAddress:USB_DIR_OUT,
|
179 |
|
|
bmAttributes:USB_ENDPOINT_XFER_BULK,
|
180 |
|
|
wMaxPacketSize:OUT_MAX_PACKET_SIZE,
|
181 |
|
|
bInterval:0x00 // ignored for bulk
|
182 |
|
|
}
|
183 |
|
|
};
|
184 |
|
|
|
185 |
|
|
static struct usb_interface_descriptor if_desc = {
|
186 |
|
|
bLength:USB_DT_INTERFACE_SIZE,
|
187 |
|
|
bDescriptorType:USB_DT_INTERFACE,
|
188 |
|
|
bInterfaceNumber:0x00,
|
189 |
|
|
bAlternateSetting:0x00,
|
190 |
|
|
bNumEndpoints:NUM_EP,
|
191 |
|
|
bInterfaceClass:0xff,
|
192 |
|
|
bInterfaceSubClass:0xab,
|
193 |
|
|
bInterfaceProtocol:0x00,
|
194 |
|
|
iInterface:0x05
|
195 |
|
|
};
|
196 |
|
|
|
197 |
|
|
static struct usb_config_descriptor config_desc = {
|
198 |
|
|
bLength:USB_DT_CONFIG_SIZE,
|
199 |
|
|
bDescriptorType:USB_DT_CONFIG,
|
200 |
|
|
wTotalLength:CONFIG_DESC_LEN,
|
201 |
|
|
bNumInterfaces:0x01,
|
202 |
|
|
bConfigurationValue:0x01,
|
203 |
|
|
iConfiguration:0x04, // configuration string
|
204 |
|
|
bmAttributes:0xc0, // self-powered
|
205 |
|
|
MaxPower:20 // 40 mA
|
206 |
|
|
};
|
207 |
|
|
|
208 |
|
|
// String[0] is a list of Language IDs supported by this device
|
209 |
|
|
static struct usb_string_descriptor string_desc0 = {
|
210 |
|
|
bLength:4,
|
211 |
|
|
bDescriptorType:USB_DT_STRING,
|
212 |
|
|
wData:{0x0409} // English, US
|
213 |
|
|
};
|
214 |
|
|
|
215 |
|
|
// These strings will be converted to Unicode in string_desc[]
|
216 |
|
|
static char *strings[5] = {
|
217 |
|
|
"Alchemy Semiconductor", // iManufacturer
|
218 |
|
|
"WutzAMattaU", // iProduct
|
219 |
|
|
"1.0.doh!", // iSerialNumber
|
220 |
|
|
"Au1000 TTY Config", // iConfiguration
|
221 |
|
|
"Au1000 TTY Interface" // iInterface
|
222 |
|
|
};
|
223 |
|
|
|
224 |
|
|
static inline int
|
225 |
|
|
port_paranoia_check(struct usb_serial_port *port, const char *function)
|
226 |
|
|
{
|
227 |
|
|
if (!port) {
|
228 |
|
|
err("%s: port is NULL", function);
|
229 |
|
|
return -1;
|
230 |
|
|
}
|
231 |
|
|
if (!port->tty) {
|
232 |
|
|
err("%s: port->tty is NULL", function);
|
233 |
|
|
return -1;
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
return 0;
|
237 |
|
|
}
|
238 |
|
|
|
239 |
|
|
|
240 |
|
|
static void
|
241 |
|
|
port_rx_callback(struct usb_serial_port *port)
|
242 |
|
|
{
|
243 |
|
|
dbg(__FUNCTION__ ": ep%d", port->out_ep_addr);
|
244 |
|
|
// mark a bh to push this data up to the tty
|
245 |
|
|
queue_task(&port->receive_complete_tq, &tq_immediate);
|
246 |
|
|
mark_bh(IMMEDIATE_BH);
|
247 |
|
|
}
|
248 |
|
|
|
249 |
|
|
static void
|
250 |
|
|
port_tx_callback(struct usb_serial_port *port, usbdev_pkt_t* pkt)
|
251 |
|
|
{
|
252 |
|
|
dbg(__FUNCTION__ ": ep%d", port->in_ep_addr);
|
253 |
|
|
// mark a bh to wakeup any tty write system call on the port.
|
254 |
|
|
queue_task(&port->send_complete_tq, &tq_immediate);
|
255 |
|
|
mark_bh(IMMEDIATE_BH);
|
256 |
|
|
|
257 |
|
|
/* free the returned packet */
|
258 |
|
|
kfree(pkt);
|
259 |
|
|
}
|
260 |
|
|
|
261 |
|
|
static void
|
262 |
|
|
usbtty_callback(usbdev_cb_type_t cb_type, unsigned long arg, void* data)
|
263 |
|
|
{
|
264 |
|
|
usbdev_pkt_t* pkt;
|
265 |
|
|
int i;
|
266 |
|
|
|
267 |
|
|
switch (cb_type) {
|
268 |
|
|
case CB_NEW_STATE:
|
269 |
|
|
dbg(__FUNCTION__ ": new dev_state=%d", (int)arg);
|
270 |
|
|
usbtty.dev_state = (usbdev_state_t)arg;
|
271 |
|
|
break;
|
272 |
|
|
case CB_PKT_COMPLETE:
|
273 |
|
|
pkt = (usbdev_pkt_t*)arg;
|
274 |
|
|
for (i=0; i<NUM_PORTS; i++) {
|
275 |
|
|
struct usb_serial_port *port = &usbtty.port[i];
|
276 |
|
|
if (pkt->ep_addr == port->in_ep_addr) {
|
277 |
|
|
port_tx_callback(port, pkt);
|
278 |
|
|
break;
|
279 |
|
|
} else if (pkt->ep_addr == port->out_ep_addr) {
|
280 |
|
|
port_rx_callback(port);
|
281 |
|
|
break;
|
282 |
|
|
}
|
283 |
|
|
}
|
284 |
|
|
break;
|
285 |
|
|
}
|
286 |
|
|
}
|
287 |
|
|
|
288 |
|
|
|
289 |
|
|
/*****************************************************************************
|
290 |
|
|
* Here begins the tty driver interface functions
|
291 |
|
|
*****************************************************************************/
|
292 |
|
|
|
293 |
|
|
static int serial_open(struct tty_struct *tty, struct file *filp)
|
294 |
|
|
{
|
295 |
|
|
int portNumber;
|
296 |
|
|
struct usb_serial_port *port;
|
297 |
|
|
unsigned long flags;
|
298 |
|
|
|
299 |
|
|
/* initialize the pointer incase something fails */
|
300 |
|
|
tty->driver_data = NULL;
|
301 |
|
|
|
302 |
|
|
MOD_INC_USE_COUNT;
|
303 |
|
|
|
304 |
|
|
/* set up our port structure making the tty driver remember
|
305 |
|
|
our port object, and us it */
|
306 |
|
|
portNumber = MINOR(tty->device);
|
307 |
|
|
port = &usbtty.port[portNumber];
|
308 |
|
|
tty->driver_data = port;
|
309 |
|
|
port->tty = tty;
|
310 |
|
|
|
311 |
|
|
if (usbtty.dev_state != CONFIGURED ||
|
312 |
|
|
port_paranoia_check(port, __FUNCTION__)) {
|
313 |
|
|
/*
|
314 |
|
|
* the device-layer must be in the configured state before
|
315 |
|
|
* the function layer can operate.
|
316 |
|
|
*/
|
317 |
|
|
MOD_DEC_USE_COUNT;
|
318 |
|
|
return -ENODEV;
|
319 |
|
|
}
|
320 |
|
|
|
321 |
|
|
dbg(__FUNCTION__ ": port %d", port->number);
|
322 |
|
|
|
323 |
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
324 |
|
|
|
325 |
|
|
++port->open_count;
|
326 |
|
|
|
327 |
|
|
if (!port->active) {
|
328 |
|
|
port->active = 1;
|
329 |
|
|
|
330 |
|
|
/*
|
331 |
|
|
* force low_latency on so that our tty_push actually forces
|
332 |
|
|
* the data through, otherwise it is scheduled, and with high
|
333 |
|
|
* data rates (like with OHCI) data can get lost.
|
334 |
|
|
*/
|
335 |
|
|
port->tty->low_latency = 1;
|
336 |
|
|
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
340 |
|
|
|
341 |
|
|
return 0;
|
342 |
|
|
}
|
343 |
|
|
|
344 |
|
|
|
345 |
|
|
static void serial_close(struct tty_struct *tty, struct file *filp)
|
346 |
|
|
{
|
347 |
|
|
struct usb_serial_port *port =
|
348 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
349 |
|
|
unsigned long flags;
|
350 |
|
|
|
351 |
|
|
dbg(__FUNCTION__ ": port %d", port->number);
|
352 |
|
|
|
353 |
|
|
if (!port->active) {
|
354 |
|
|
err(__FUNCTION__ ": port not opened");
|
355 |
|
|
return;
|
356 |
|
|
}
|
357 |
|
|
|
358 |
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
359 |
|
|
|
360 |
|
|
--port->open_count;
|
361 |
|
|
|
362 |
|
|
if (port->open_count <= 0) {
|
363 |
|
|
port->active = 0;
|
364 |
|
|
port->open_count = 0;
|
365 |
|
|
}
|
366 |
|
|
|
367 |
|
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
368 |
|
|
MOD_DEC_USE_COUNT;
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
|
372 |
|
|
static int serial_write(struct tty_struct *tty, int from_user,
|
373 |
|
|
const unsigned char *buf, int count)
|
374 |
|
|
{
|
375 |
|
|
struct usb_serial_port *port =
|
376 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
377 |
|
|
usbdev_pkt_t* pkt;
|
378 |
|
|
int max_pkt_sz, ret;
|
379 |
|
|
unsigned long flags;
|
380 |
|
|
|
381 |
|
|
/*
|
382 |
|
|
* the device-layer must be in the configured state before the
|
383 |
|
|
* function layer can operate.
|
384 |
|
|
*/
|
385 |
|
|
if (usbtty.dev_state != CONFIGURED)
|
386 |
|
|
return -ENODEV;
|
387 |
|
|
|
388 |
|
|
if (!port->active) {
|
389 |
|
|
err(__FUNCTION__ ": port not open");
|
390 |
|
|
return -EINVAL;
|
391 |
|
|
}
|
392 |
|
|
|
393 |
|
|
if (count == 0) {
|
394 |
|
|
dbg(__FUNCTION__ ": request of 0 bytes");
|
395 |
|
|
return (0);
|
396 |
|
|
}
|
397 |
|
|
|
398 |
|
|
#if 0
|
399 |
|
|
if (port->writing) {
|
400 |
|
|
dbg(__FUNCTION__ ": already writing");
|
401 |
|
|
return 0;
|
402 |
|
|
}
|
403 |
|
|
#endif
|
404 |
|
|
|
405 |
|
|
max_pkt_sz = port->in_desc->wMaxPacketSize;
|
406 |
|
|
count = (count > max_pkt_sz) ? max_pkt_sz : count;
|
407 |
|
|
|
408 |
|
|
if ((ret = usbdev_alloc_packet(port->in_ep_addr, count, &pkt)))
|
409 |
|
|
return ret;
|
410 |
|
|
|
411 |
|
|
if (from_user)
|
412 |
|
|
copy_from_user(pkt->payload, buf, count);
|
413 |
|
|
else
|
414 |
|
|
memcpy(pkt->payload, buf, count);
|
415 |
|
|
|
416 |
|
|
ret = usbdev_send_packet(port->in_ep_addr, pkt);
|
417 |
|
|
|
418 |
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
419 |
|
|
port->writing = 1;
|
420 |
|
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
421 |
|
|
|
422 |
|
|
return ret;
|
423 |
|
|
}
|
424 |
|
|
|
425 |
|
|
|
426 |
|
|
static int serial_write_room(struct tty_struct *tty)
|
427 |
|
|
{
|
428 |
|
|
struct usb_serial_port *port =
|
429 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
430 |
|
|
int room = 0;
|
431 |
|
|
|
432 |
|
|
/*
|
433 |
|
|
* the device-layer must be in the configured state before the
|
434 |
|
|
* function layer can operate.
|
435 |
|
|
*/
|
436 |
|
|
if (usbtty.dev_state != CONFIGURED)
|
437 |
|
|
return -ENODEV;
|
438 |
|
|
|
439 |
|
|
if (!port->active) {
|
440 |
|
|
err(__FUNCTION__ ": port not open");
|
441 |
|
|
return -EINVAL;
|
442 |
|
|
}
|
443 |
|
|
|
444 |
|
|
//room = port->writing ? 0 : port->in_desc->wMaxPacketSize;
|
445 |
|
|
room = port->in_desc->wMaxPacketSize;
|
446 |
|
|
|
447 |
|
|
dbg(__FUNCTION__ ": %d", room);
|
448 |
|
|
return room;
|
449 |
|
|
}
|
450 |
|
|
|
451 |
|
|
|
452 |
|
|
static int serial_chars_in_buffer(struct tty_struct *tty)
|
453 |
|
|
{
|
454 |
|
|
struct usb_serial_port *port =
|
455 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
456 |
|
|
int chars = 0;
|
457 |
|
|
|
458 |
|
|
/*
|
459 |
|
|
* the device-layer must be in the configured state before the
|
460 |
|
|
* function layer can operate.
|
461 |
|
|
*/
|
462 |
|
|
if (usbtty.dev_state != CONFIGURED)
|
463 |
|
|
return -ENODEV;
|
464 |
|
|
|
465 |
|
|
if (!port->active) {
|
466 |
|
|
err(__FUNCTION__ ": port not open");
|
467 |
|
|
return -EINVAL;
|
468 |
|
|
}
|
469 |
|
|
|
470 |
|
|
//chars = port->writing ? usbdev_get_byte_count(port->in_ep_addr) : 0;
|
471 |
|
|
chars = usbdev_get_byte_count(port->in_ep_addr);
|
472 |
|
|
|
473 |
|
|
dbg(__FUNCTION__ ": %d", chars);
|
474 |
|
|
return chars;
|
475 |
|
|
}
|
476 |
|
|
|
477 |
|
|
|
478 |
|
|
static void serial_throttle(struct tty_struct *tty)
|
479 |
|
|
{
|
480 |
|
|
struct usb_serial_port *port =
|
481 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
482 |
|
|
|
483 |
|
|
if (!port->active || usbtty.dev_state != CONFIGURED) {
|
484 |
|
|
err(__FUNCTION__ ": port not open");
|
485 |
|
|
return;
|
486 |
|
|
}
|
487 |
|
|
|
488 |
|
|
// FIXME: anything to do?
|
489 |
|
|
dbg(__FUNCTION__);
|
490 |
|
|
}
|
491 |
|
|
|
492 |
|
|
|
493 |
|
|
static void serial_unthrottle(struct tty_struct *tty)
|
494 |
|
|
{
|
495 |
|
|
struct usb_serial_port *port =
|
496 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
497 |
|
|
|
498 |
|
|
if (!port->active || usbtty.dev_state != CONFIGURED) {
|
499 |
|
|
err(__FUNCTION__ ": port not open");
|
500 |
|
|
return;
|
501 |
|
|
}
|
502 |
|
|
|
503 |
|
|
// FIXME: anything to do?
|
504 |
|
|
dbg(__FUNCTION__);
|
505 |
|
|
}
|
506 |
|
|
|
507 |
|
|
|
508 |
|
|
static int serial_ioctl(struct tty_struct *tty, struct file *file,
|
509 |
|
|
unsigned int cmd, unsigned long arg)
|
510 |
|
|
{
|
511 |
|
|
struct usb_serial_port *port =
|
512 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
513 |
|
|
|
514 |
|
|
if (!port->active) {
|
515 |
|
|
err(__FUNCTION__ ": port not open");
|
516 |
|
|
return -ENODEV;
|
517 |
|
|
}
|
518 |
|
|
// FIXME: need any IOCTLs?
|
519 |
|
|
dbg(__FUNCTION__);
|
520 |
|
|
|
521 |
|
|
return -ENOIOCTLCMD;
|
522 |
|
|
}
|
523 |
|
|
|
524 |
|
|
|
525 |
|
|
static void serial_set_termios(struct tty_struct *tty, struct termios *old)
|
526 |
|
|
{
|
527 |
|
|
struct usb_serial_port *port =
|
528 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
529 |
|
|
|
530 |
|
|
if (!port->active || usbtty.dev_state != CONFIGURED) {
|
531 |
|
|
err(__FUNCTION__ ": port not open");
|
532 |
|
|
return;
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
dbg(__FUNCTION__);
|
536 |
|
|
// FIXME: anything to do?
|
537 |
|
|
}
|
538 |
|
|
|
539 |
|
|
|
540 |
|
|
static void serial_break(struct tty_struct *tty, int break_state)
|
541 |
|
|
{
|
542 |
|
|
struct usb_serial_port *port =
|
543 |
|
|
(struct usb_serial_port *) tty->driver_data;
|
544 |
|
|
|
545 |
|
|
if (!port->active || usbtty.dev_state != CONFIGURED) {
|
546 |
|
|
err(__FUNCTION__ ": port not open");
|
547 |
|
|
return;
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
dbg(__FUNCTION__);
|
551 |
|
|
// FIXME: anything to do?
|
552 |
|
|
}
|
553 |
|
|
|
554 |
|
|
|
555 |
|
|
static void port_send_complete(void *private)
|
556 |
|
|
{
|
557 |
|
|
struct usb_serial_port *port = (struct usb_serial_port *) private;
|
558 |
|
|
struct tty_struct *tty;
|
559 |
|
|
unsigned long flags;
|
560 |
|
|
|
561 |
|
|
dbg(__FUNCTION__ ": port %d, ep%d", port->number, port->in_ep_addr);
|
562 |
|
|
|
563 |
|
|
tty = port->tty;
|
564 |
|
|
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
565 |
|
|
tty->ldisc.write_wakeup) {
|
566 |
|
|
dbg(__FUNCTION__ ": write wakeup call.");
|
567 |
|
|
(tty->ldisc.write_wakeup) (tty);
|
568 |
|
|
}
|
569 |
|
|
|
570 |
|
|
wake_up_interruptible(&tty->write_wait);
|
571 |
|
|
|
572 |
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
573 |
|
|
port->writing = usbdev_get_byte_count(port->in_ep_addr) <= 0 ? 0 : 1;
|
574 |
|
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
|
578 |
|
|
static void port_receive_complete(void *private)
|
579 |
|
|
{
|
580 |
|
|
struct usb_serial_port *port = (struct usb_serial_port *) private;
|
581 |
|
|
struct tty_struct *tty = port->tty;
|
582 |
|
|
usbdev_pkt_t* pkt = NULL;
|
583 |
|
|
int i, count;
|
584 |
|
|
|
585 |
|
|
/* while there is a packet available */
|
586 |
|
|
while ((count = usbdev_receive_packet(port->out_ep_addr,
|
587 |
|
|
&pkt)) != -ENODATA) {
|
588 |
|
|
if (count < 0) {
|
589 |
|
|
if (pkt)
|
590 |
|
|
kfree(pkt);
|
591 |
|
|
break; /* exit if error other than ENODATA */
|
592 |
|
|
}
|
593 |
|
|
|
594 |
|
|
dbg(__FUNCTION__ ": port %d, ep%d, size=%d",
|
595 |
|
|
port->number, port->out_ep_addr, count);
|
596 |
|
|
|
597 |
|
|
for (i = 0; i < count; i++) {
|
598 |
|
|
/* if we insert more than TTY_FLIPBUF_SIZE characters,
|
599 |
|
|
we drop them. */
|
600 |
|
|
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
|
601 |
|
|
tty_flip_buffer_push(tty);
|
602 |
|
|
}
|
603 |
|
|
/* this doesn't actually push the data through
|
604 |
|
|
unless tty->low_latency is set */
|
605 |
|
|
tty_insert_flip_char(tty, pkt->payload[i], 0);
|
606 |
|
|
}
|
607 |
|
|
tty_flip_buffer_push(tty);
|
608 |
|
|
|
609 |
|
|
kfree(pkt); /* make sure we free the packet */
|
610 |
|
|
}
|
611 |
|
|
|
612 |
|
|
}
|
613 |
|
|
|
614 |
|
|
|
615 |
|
|
static struct tty_driver serial_tty_driver = {
|
616 |
|
|
magic:TTY_DRIVER_MAGIC,
|
617 |
|
|
driver_name:"usbfn-tty",
|
618 |
|
|
name:"usb/ttsdev/%d",
|
619 |
|
|
major:SERIAL_TTY_MAJOR,
|
620 |
|
|
minor_start:0,
|
621 |
|
|
num:NUM_PORTS,
|
622 |
|
|
type:TTY_DRIVER_TYPE_SERIAL,
|
623 |
|
|
subtype:SERIAL_TYPE_NORMAL,
|
624 |
|
|
flags:TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
|
625 |
|
|
refcount:&serial_refcount,
|
626 |
|
|
table:serial_tty,
|
627 |
|
|
termios:serial_termios,
|
628 |
|
|
termios_locked:serial_termios_locked,
|
629 |
|
|
|
630 |
|
|
open:serial_open,
|
631 |
|
|
close:serial_close,
|
632 |
|
|
write:serial_write,
|
633 |
|
|
write_room:serial_write_room,
|
634 |
|
|
ioctl:serial_ioctl,
|
635 |
|
|
set_termios:serial_set_termios,
|
636 |
|
|
throttle:serial_throttle,
|
637 |
|
|
unthrottle:serial_unthrottle,
|
638 |
|
|
break_ctl:serial_break,
|
639 |
|
|
chars_in_buffer:serial_chars_in_buffer,
|
640 |
|
|
};
|
641 |
|
|
|
642 |
|
|
|
643 |
|
|
void usbfn_tty_exit(void)
|
644 |
|
|
{
|
645 |
|
|
int i;
|
646 |
|
|
|
647 |
|
|
/* kill the device layer */
|
648 |
|
|
usbdev_exit();
|
649 |
|
|
|
650 |
|
|
for (i=0; i < NUM_PORTS; i++) {
|
651 |
|
|
tty_unregister_devfs(&serial_tty_driver, i);
|
652 |
|
|
info("usb serial converter now disconnected from ttyUSBdev%d",
|
653 |
|
|
i);
|
654 |
|
|
}
|
655 |
|
|
|
656 |
|
|
tty_unregister_driver(&serial_tty_driver);
|
657 |
|
|
|
658 |
|
|
if (usbtty.str_desc_buf)
|
659 |
|
|
kfree(usbtty.str_desc_buf);
|
660 |
|
|
}
|
661 |
|
|
|
662 |
|
|
|
663 |
|
|
int usbfn_tty_init(void)
|
664 |
|
|
{
|
665 |
|
|
int ret = 0, i, str_desc_len;
|
666 |
|
|
|
667 |
|
|
/* register the tty driver */
|
668 |
|
|
serial_tty_driver.init_termios = tty_std_termios;
|
669 |
|
|
serial_tty_driver.init_termios.c_cflag =
|
670 |
|
|
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
671 |
|
|
|
672 |
|
|
if (tty_register_driver(&serial_tty_driver)) {
|
673 |
|
|
err(__FUNCTION__ ": failed to register tty driver");
|
674 |
|
|
ret = -ENXIO;
|
675 |
|
|
goto out;
|
676 |
|
|
}
|
677 |
|
|
|
678 |
|
|
/*
|
679 |
|
|
* initialize pointers to descriptors
|
680 |
|
|
*/
|
681 |
|
|
usbtty.dev_desc = &dev_desc;
|
682 |
|
|
usbtty.config_desc = &config_desc;
|
683 |
|
|
usbtty.if_desc = &if_desc;
|
684 |
|
|
|
685 |
|
|
/*
|
686 |
|
|
* initialize the string descriptors
|
687 |
|
|
*/
|
688 |
|
|
|
689 |
|
|
/* alloc buffer big enough for all string descriptors */
|
690 |
|
|
str_desc_len = string_desc0.bLength;
|
691 |
|
|
for (i = 0; i < 5; i++)
|
692 |
|
|
str_desc_len += 2 + 2 * strlen(strings[i]);
|
693 |
|
|
usbtty.str_desc_buf = (void *) kmalloc(str_desc_len, GFP_KERNEL);
|
694 |
|
|
if (!usbtty.str_desc_buf) {
|
695 |
|
|
err(__FUNCTION__ ": failed to alloc string descriptors");
|
696 |
|
|
ret = -ENOMEM;
|
697 |
|
|
goto out;
|
698 |
|
|
}
|
699 |
|
|
|
700 |
|
|
usbtty.str_desc[0] =
|
701 |
|
|
(struct usb_string_descriptor *)usbtty.str_desc_buf;
|
702 |
|
|
memcpy(usbtty.str_desc[0], &string_desc0, string_desc0.bLength);
|
703 |
|
|
usbtty.str_desc[1] = (struct usb_string_descriptor *)
|
704 |
|
|
(usbtty.str_desc_buf + string_desc0.bLength);
|
705 |
|
|
for (i = 1; i < 6; i++) {
|
706 |
|
|
struct usb_string_descriptor *desc = usbtty.str_desc[i];
|
707 |
|
|
char *str = strings[i - 1];
|
708 |
|
|
int j, str_len = strlen(str);
|
709 |
|
|
|
710 |
|
|
desc->bLength = 2 + 2 * str_len;
|
711 |
|
|
desc->bDescriptorType = USB_DT_STRING;
|
712 |
|
|
for (j = 0; j < str_len; j++) {
|
713 |
|
|
desc->wData[j] = (u16) str[j];
|
714 |
|
|
}
|
715 |
|
|
if (i < 5)
|
716 |
|
|
usbtty.str_desc[i + 1] =
|
717 |
|
|
(struct usb_string_descriptor *)
|
718 |
|
|
((u8 *) desc + desc->bLength);
|
719 |
|
|
}
|
720 |
|
|
|
721 |
|
|
/*
|
722 |
|
|
* start the device layer. The device layer assigns us
|
723 |
|
|
* our endpoint addresses
|
724 |
|
|
*/
|
725 |
|
|
if ((ret = usbdev_init(&dev_desc, &config_desc, &if_desc, ep_desc,
|
726 |
|
|
usbtty.str_desc, usbtty_callback, NULL))) {
|
727 |
|
|
err(__FUNCTION__ ": device-layer init failed");
|
728 |
|
|
goto out;
|
729 |
|
|
}
|
730 |
|
|
|
731 |
|
|
/* initialize the devfs nodes for this device and let the user
|
732 |
|
|
know what ports we are bound to */
|
733 |
|
|
for (i = 0; i < NUM_PORTS; ++i) {
|
734 |
|
|
struct usb_serial_port *port;
|
735 |
|
|
tty_register_devfs(&serial_tty_driver, 0, i);
|
736 |
|
|
info("usbdev serial attached to ttyUSBdev%d "
|
737 |
|
|
"(or devfs usb/ttsdev/%d)", i, i);
|
738 |
|
|
port = &usbtty.port[i];
|
739 |
|
|
port->number = i;
|
740 |
|
|
port->in_desc = &ep_desc[NUM_PORTS*i];
|
741 |
|
|
port->out_desc = &ep_desc[NUM_PORTS*i + 1];
|
742 |
|
|
port->in_ep_addr = port->in_desc->bEndpointAddress & 0x0f;
|
743 |
|
|
port->out_ep_addr = port->out_desc->bEndpointAddress & 0x0f;
|
744 |
|
|
port->send_complete_tq.routine = port_send_complete;
|
745 |
|
|
port->send_complete_tq.data = port;
|
746 |
|
|
port->receive_complete_tq.routine = port_receive_complete;
|
747 |
|
|
port->receive_complete_tq.data = port;
|
748 |
|
|
spin_lock_init(&port->port_lock);
|
749 |
|
|
}
|
750 |
|
|
|
751 |
|
|
out:
|
752 |
|
|
if (ret)
|
753 |
|
|
usbfn_tty_exit();
|
754 |
|
|
return ret;
|
755 |
|
|
}
|
756 |
|
|
|
757 |
|
|
|
758 |
|
|
/* Module information */
|
759 |
|
|
MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com");
|
760 |
|
|
MODULE_DESCRIPTION("Au1x00 USB Device-Side Serial TTY Driver");
|
761 |
|
|
MODULE_LICENSE("GPL");
|
762 |
|
|
|
763 |
|
|
module_init(usbfn_tty_init);
|
764 |
|
|
module_exit(usbfn_tty_exit);
|