root / hw / usb-serial.c @ 59d94130
History | View | Annotate | Download (16.8 kB)
1 | a7954218 | balrog | /*
|
---|---|---|---|
2 | a7954218 | balrog | * FTDI FT232BM Device emulation
|
3 | a7954218 | balrog | *
|
4 | a7954218 | balrog | * Copyright (c) 2006 CodeSourcery.
|
5 | a7954218 | balrog | * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
|
6 | a7954218 | balrog | * Written by Paul Brook, reused for FTDI by Samuel Thibault
|
7 | a7954218 | balrog | *
|
8 | a7954218 | balrog | * This code is licenced under the LGPL.
|
9 | a7954218 | balrog | */
|
10 | a7954218 | balrog | |
11 | a7954218 | balrog | #include "qemu-common.h" |
12 | a7954218 | balrog | #include "usb.h" |
13 | a7954218 | balrog | #include "qemu-char.h" |
14 | a7954218 | balrog | |
15 | a7954218 | balrog | //#define DEBUG_Serial
|
16 | a7954218 | balrog | |
17 | a7954218 | balrog | #ifdef DEBUG_Serial
|
18 | a7954218 | balrog | #define DPRINTF(fmt, args...) \
|
19 | a7954218 | balrog | do { printf("usb-serial: " fmt , ##args); } while (0) |
20 | a7954218 | balrog | #else
|
21 | a7954218 | balrog | #define DPRINTF(fmt, args...) do {} while(0) |
22 | a7954218 | balrog | #endif
|
23 | a7954218 | balrog | |
24 | a7954218 | balrog | #define RECV_BUF 384 |
25 | a7954218 | balrog | |
26 | a7954218 | balrog | /* Commands */
|
27 | a7954218 | balrog | #define FTDI_RESET 0 |
28 | a7954218 | balrog | #define FTDI_SET_MDM_CTRL 1 |
29 | a7954218 | balrog | #define FTDI_SET_FLOW_CTRL 2 |
30 | a7954218 | balrog | #define FTDI_SET_BAUD 3 |
31 | a7954218 | balrog | #define FTDI_SET_DATA 4 |
32 | a7954218 | balrog | #define FTDI_GET_MDM_ST 5 |
33 | a7954218 | balrog | #define FTDI_SET_EVENT_CHR 6 |
34 | a7954218 | balrog | #define FTDI_SET_ERROR_CHR 7 |
35 | a7954218 | balrog | #define FTDI_SET_LATENCY 9 |
36 | a7954218 | balrog | #define FTDI_GET_LATENCY 10 |
37 | a7954218 | balrog | |
38 | a7954218 | balrog | #define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) |
39 | a7954218 | balrog | #define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) |
40 | a7954218 | balrog | |
41 | a7954218 | balrog | /* RESET */
|
42 | a7954218 | balrog | |
43 | a7954218 | balrog | #define FTDI_RESET_SIO 0 |
44 | a7954218 | balrog | #define FTDI_RESET_RX 1 |
45 | a7954218 | balrog | #define FTDI_RESET_TX 2 |
46 | a7954218 | balrog | |
47 | a7954218 | balrog | /* SET_MDM_CTRL */
|
48 | a7954218 | balrog | |
49 | a7954218 | balrog | #define FTDI_DTR 1 |
50 | abb8a139 | aurel32 | #define FTDI_SET_DTR (FTDI_DTR << 8) |
51 | a7954218 | balrog | #define FTDI_RTS 2 |
52 | abb8a139 | aurel32 | #define FTDI_SET_RTS (FTDI_RTS << 8) |
53 | a7954218 | balrog | |
54 | a7954218 | balrog | /* SET_FLOW_CTRL */
|
55 | a7954218 | balrog | |
56 | a7954218 | balrog | #define FTDI_RTS_CTS_HS 1 |
57 | a7954218 | balrog | #define FTDI_DTR_DSR_HS 2 |
58 | a7954218 | balrog | #define FTDI_XON_XOFF_HS 4 |
59 | a7954218 | balrog | |
60 | a7954218 | balrog | /* SET_DATA */
|
61 | a7954218 | balrog | |
62 | a7954218 | balrog | #define FTDI_PARITY (0x7 << 8) |
63 | a7954218 | balrog | #define FTDI_ODD (0x1 << 8) |
64 | a7954218 | balrog | #define FTDI_EVEN (0x2 << 8) |
65 | a7954218 | balrog | #define FTDI_MARK (0x3 << 8) |
66 | a7954218 | balrog | #define FTDI_SPACE (0x4 << 8) |
67 | a7954218 | balrog | |
68 | a7954218 | balrog | #define FTDI_STOP (0x3 << 11) |
69 | a7954218 | balrog | #define FTDI_STOP1 (0x0 << 11) |
70 | a7954218 | balrog | #define FTDI_STOP15 (0x1 << 11) |
71 | a7954218 | balrog | #define FTDI_STOP2 (0x2 << 11) |
72 | a7954218 | balrog | |
73 | a7954218 | balrog | /* GET_MDM_ST */
|
74 | a7954218 | balrog | /* TODO: should be sent every 40ms */
|
75 | a7954218 | balrog | #define FTDI_CTS (1<<4) // CTS line status |
76 | a7954218 | balrog | #define FTDI_DSR (1<<5) // DSR line status |
77 | a7954218 | balrog | #define FTDI_RI (1<<6) // RI line status |
78 | a7954218 | balrog | #define FTDI_RLSD (1<<7) // Receive Line Signal Detect |
79 | a7954218 | balrog | |
80 | a7954218 | balrog | /* Status */
|
81 | a7954218 | balrog | |
82 | a7954218 | balrog | #define FTDI_DR (1<<0) // Data Ready |
83 | a7954218 | balrog | #define FTDI_OE (1<<1) // Overrun Err |
84 | a7954218 | balrog | #define FTDI_PE (1<<2) // Parity Err |
85 | a7954218 | balrog | #define FTDI_FE (1<<3) // Framing Err |
86 | a7954218 | balrog | #define FTDI_BI (1<<4) // Break Interrupt |
87 | a7954218 | balrog | #define FTDI_THRE (1<<5) // Transmitter Holding Register |
88 | a7954218 | balrog | #define FTDI_TEMT (1<<6) // Transmitter Empty |
89 | a7954218 | balrog | #define FTDI_FIFO (1<<7) // Error in FIFO |
90 | a7954218 | balrog | |
91 | a7954218 | balrog | typedef struct { |
92 | a7954218 | balrog | USBDevice dev; |
93 | a7954218 | balrog | uint16_t vendorid; |
94 | a7954218 | balrog | uint16_t productid; |
95 | a7954218 | balrog | uint8_t recv_buf[RECV_BUF]; |
96 | 8109b9b6 | aurel32 | uint16_t recv_ptr; |
97 | 8109b9b6 | aurel32 | uint16_t recv_used; |
98 | a7954218 | balrog | uint8_t event_chr; |
99 | a7954218 | balrog | uint8_t error_chr; |
100 | a7954218 | balrog | uint8_t event_trigger; |
101 | a7954218 | balrog | QEMUSerialSetParams params; |
102 | a7954218 | balrog | int latency; /* ms */ |
103 | a7954218 | balrog | CharDriverState *cs; |
104 | a7954218 | balrog | } USBSerialState; |
105 | a7954218 | balrog | |
106 | a7954218 | balrog | static const uint8_t qemu_serial_dev_descriptor[] = { |
107 | a7954218 | balrog | 0x12, /* u8 bLength; */ |
108 | a7954218 | balrog | 0x01, /* u8 bDescriptorType; Device */ |
109 | a7954218 | balrog | 0x00, 0x02, /* u16 bcdUSB; v2.0 */ |
110 | a7954218 | balrog | |
111 | a7954218 | balrog | 0x00, /* u8 bDeviceClass; */ |
112 | a7954218 | balrog | 0x00, /* u8 bDeviceSubClass; */ |
113 | a7954218 | balrog | 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ |
114 | a7954218 | balrog | 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ |
115 | a7954218 | balrog | |
116 | a7954218 | balrog | /* Vendor and product id are arbitrary. */
|
117 | a7954218 | balrog | 0x03, 0x04, /* u16 idVendor; */ |
118 | a7954218 | balrog | 0x00, 0xFF, /* u16 idProduct; */ |
119 | a7954218 | balrog | 0x00, 0x04, /* u16 bcdDevice */ |
120 | a7954218 | balrog | |
121 | a7954218 | balrog | 0x01, /* u8 iManufacturer; */ |
122 | a7954218 | balrog | 0x02, /* u8 iProduct; */ |
123 | a7954218 | balrog | 0x03, /* u8 iSerialNumber; */ |
124 | a7954218 | balrog | 0x01 /* u8 bNumConfigurations; */ |
125 | a7954218 | balrog | }; |
126 | a7954218 | balrog | |
127 | a7954218 | balrog | static const uint8_t qemu_serial_config_descriptor[] = { |
128 | a7954218 | balrog | |
129 | a7954218 | balrog | /* one configuration */
|
130 | a7954218 | balrog | 0x09, /* u8 bLength; */ |
131 | a7954218 | balrog | 0x02, /* u8 bDescriptorType; Configuration */ |
132 | a7954218 | balrog | 0x20, 0x00, /* u16 wTotalLength; */ |
133 | a7954218 | balrog | 0x01, /* u8 bNumInterfaces; (1) */ |
134 | a7954218 | balrog | 0x01, /* u8 bConfigurationValue; */ |
135 | a7954218 | balrog | 0x00, /* u8 iConfiguration; */ |
136 | a7954218 | balrog | 0x80, /* u8 bmAttributes; |
137 | a7954218 | balrog | Bit 7: must be set,
|
138 | a7954218 | balrog | 6: Self-powered,
|
139 | a7954218 | balrog | 5: Remote wakeup,
|
140 | a7954218 | balrog | 4..0: resvd */
|
141 | a7954218 | balrog | 100/2, /* u8 MaxPower; */ |
142 | a7954218 | balrog | |
143 | a7954218 | balrog | /* one interface */
|
144 | a7954218 | balrog | 0x09, /* u8 if_bLength; */ |
145 | a7954218 | balrog | 0x04, /* u8 if_bDescriptorType; Interface */ |
146 | a7954218 | balrog | 0x00, /* u8 if_bInterfaceNumber; */ |
147 | a7954218 | balrog | 0x00, /* u8 if_bAlternateSetting; */ |
148 | a7954218 | balrog | 0x02, /* u8 if_bNumEndpoints; */ |
149 | a7954218 | balrog | 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ |
150 | a7954218 | balrog | 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */ |
151 | a7954218 | balrog | 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */ |
152 | a7954218 | balrog | 0x02, /* u8 if_iInterface; */ |
153 | a7954218 | balrog | |
154 | a7954218 | balrog | /* Bulk-In endpoint */
|
155 | a7954218 | balrog | 0x07, /* u8 ep_bLength; */ |
156 | a7954218 | balrog | 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
157 | a7954218 | balrog | 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ |
158 | a7954218 | balrog | 0x02, /* u8 ep_bmAttributes; Bulk */ |
159 | a7954218 | balrog | 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ |
160 | a7954218 | balrog | 0x00, /* u8 ep_bInterval; */ |
161 | a7954218 | balrog | |
162 | a7954218 | balrog | /* Bulk-Out endpoint */
|
163 | a7954218 | balrog | 0x07, /* u8 ep_bLength; */ |
164 | a7954218 | balrog | 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
165 | a7954218 | balrog | 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ |
166 | a7954218 | balrog | 0x02, /* u8 ep_bmAttributes; Bulk */ |
167 | a7954218 | balrog | 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ |
168 | a7954218 | balrog | 0x00 /* u8 ep_bInterval; */ |
169 | a7954218 | balrog | }; |
170 | a7954218 | balrog | |
171 | a7954218 | balrog | static void usb_serial_reset(USBSerialState *s) |
172 | a7954218 | balrog | { |
173 | a7954218 | balrog | /* TODO: Set flow control to none */
|
174 | a7954218 | balrog | s->event_chr = 0x0d;
|
175 | a7954218 | balrog | s->event_trigger = 0;
|
176 | a7954218 | balrog | s->recv_ptr = 0;
|
177 | a7954218 | balrog | s->recv_used = 0;
|
178 | a7954218 | balrog | /* TODO: purge in char driver */
|
179 | a7954218 | balrog | } |
180 | a7954218 | balrog | |
181 | a7954218 | balrog | static void usb_serial_handle_reset(USBDevice *dev) |
182 | a7954218 | balrog | { |
183 | a7954218 | balrog | USBSerialState *s = (USBSerialState *)dev; |
184 | a7954218 | balrog | |
185 | a7954218 | balrog | DPRINTF("Reset\n");
|
186 | a7954218 | balrog | |
187 | a7954218 | balrog | usb_serial_reset(s); |
188 | a7954218 | balrog | /* TODO: Reset char device, send BREAK? */
|
189 | a7954218 | balrog | } |
190 | a7954218 | balrog | |
191 | abb8a139 | aurel32 | static uint8_t usb_get_modem_lines(USBSerialState *s)
|
192 | abb8a139 | aurel32 | { |
193 | abb8a139 | aurel32 | int flags;
|
194 | abb8a139 | aurel32 | uint8_t ret; |
195 | abb8a139 | aurel32 | |
196 | abb8a139 | aurel32 | if (qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
|
197 | abb8a139 | aurel32 | return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
|
198 | abb8a139 | aurel32 | |
199 | abb8a139 | aurel32 | ret = 0;
|
200 | abb8a139 | aurel32 | if (flags & CHR_TIOCM_CTS)
|
201 | abb8a139 | aurel32 | ret |= FTDI_CTS; |
202 | abb8a139 | aurel32 | if (flags & CHR_TIOCM_DSR)
|
203 | abb8a139 | aurel32 | ret |= FTDI_DSR; |
204 | abb8a139 | aurel32 | if (flags & CHR_TIOCM_RI)
|
205 | abb8a139 | aurel32 | ret |= FTDI_RI; |
206 | abb8a139 | aurel32 | if (flags & CHR_TIOCM_CAR)
|
207 | abb8a139 | aurel32 | ret |= FTDI_RLSD; |
208 | abb8a139 | aurel32 | |
209 | abb8a139 | aurel32 | return ret;
|
210 | abb8a139 | aurel32 | } |
211 | abb8a139 | aurel32 | |
212 | a7954218 | balrog | static int usb_serial_handle_control(USBDevice *dev, int request, int value, |
213 | a7954218 | balrog | int index, int length, uint8_t *data) |
214 | a7954218 | balrog | { |
215 | a7954218 | balrog | USBSerialState *s = (USBSerialState *)dev; |
216 | a7954218 | balrog | int ret = 0; |
217 | a7954218 | balrog | |
218 | a7954218 | balrog | //DPRINTF("got control %x, value %x\n",request, value);
|
219 | a7954218 | balrog | switch (request) {
|
220 | a7954218 | balrog | case DeviceRequest | USB_REQ_GET_STATUS:
|
221 | a7954218 | balrog | data[0] = (0 << USB_DEVICE_SELF_POWERED) | |
222 | a7954218 | balrog | (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); |
223 | a7954218 | balrog | data[1] = 0x00; |
224 | a7954218 | balrog | ret = 2;
|
225 | a7954218 | balrog | break;
|
226 | a7954218 | balrog | case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
227 | a7954218 | balrog | if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
228 | a7954218 | balrog | dev->remote_wakeup = 0;
|
229 | a7954218 | balrog | } else {
|
230 | a7954218 | balrog | goto fail;
|
231 | a7954218 | balrog | } |
232 | a7954218 | balrog | ret = 0;
|
233 | a7954218 | balrog | break;
|
234 | a7954218 | balrog | case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
235 | a7954218 | balrog | if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
236 | a7954218 | balrog | dev->remote_wakeup = 1;
|
237 | a7954218 | balrog | } else {
|
238 | a7954218 | balrog | goto fail;
|
239 | a7954218 | balrog | } |
240 | a7954218 | balrog | ret = 0;
|
241 | a7954218 | balrog | break;
|
242 | a7954218 | balrog | case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
243 | a7954218 | balrog | dev->addr = value; |
244 | a7954218 | balrog | ret = 0;
|
245 | a7954218 | balrog | break;
|
246 | a7954218 | balrog | case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
247 | a7954218 | balrog | switch(value >> 8) { |
248 | a7954218 | balrog | case USB_DT_DEVICE:
|
249 | a7954218 | balrog | memcpy(data, qemu_serial_dev_descriptor, |
250 | a7954218 | balrog | sizeof(qemu_serial_dev_descriptor));
|
251 | a7954218 | balrog | data[8] = s->vendorid & 0xff; |
252 | a7954218 | balrog | data[9] = ((s->vendorid) >> 8) & 0xff; |
253 | a7954218 | balrog | data[10] = s->productid & 0xff; |
254 | a7954218 | balrog | data[11] = ((s->productid) >> 8) & 0xff; |
255 | a7954218 | balrog | ret = sizeof(qemu_serial_dev_descriptor);
|
256 | a7954218 | balrog | break;
|
257 | a7954218 | balrog | case USB_DT_CONFIG:
|
258 | a7954218 | balrog | memcpy(data, qemu_serial_config_descriptor, |
259 | a7954218 | balrog | sizeof(qemu_serial_config_descriptor));
|
260 | a7954218 | balrog | ret = sizeof(qemu_serial_config_descriptor);
|
261 | a7954218 | balrog | break;
|
262 | a7954218 | balrog | case USB_DT_STRING:
|
263 | a7954218 | balrog | switch(value & 0xff) { |
264 | a7954218 | balrog | case 0: |
265 | a7954218 | balrog | /* language ids */
|
266 | a7954218 | balrog | data[0] = 4; |
267 | a7954218 | balrog | data[1] = 3; |
268 | a7954218 | balrog | data[2] = 0x09; |
269 | a7954218 | balrog | data[3] = 0x04; |
270 | a7954218 | balrog | ret = 4;
|
271 | a7954218 | balrog | break;
|
272 | a7954218 | balrog | case 1: |
273 | a7954218 | balrog | /* vendor description */
|
274 | a7954218 | balrog | ret = set_usb_string(data, "QEMU " QEMU_VERSION);
|
275 | a7954218 | balrog | break;
|
276 | a7954218 | balrog | case 2: |
277 | a7954218 | balrog | /* product description */
|
278 | a7954218 | balrog | ret = set_usb_string(data, "QEMU USB SERIAL");
|
279 | a7954218 | balrog | break;
|
280 | a7954218 | balrog | case 3: |
281 | a7954218 | balrog | /* serial number */
|
282 | a7954218 | balrog | ret = set_usb_string(data, "1");
|
283 | a7954218 | balrog | break;
|
284 | a7954218 | balrog | default:
|
285 | a7954218 | balrog | goto fail;
|
286 | a7954218 | balrog | } |
287 | a7954218 | balrog | break;
|
288 | a7954218 | balrog | default:
|
289 | a7954218 | balrog | goto fail;
|
290 | a7954218 | balrog | } |
291 | a7954218 | balrog | break;
|
292 | a7954218 | balrog | case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
293 | a7954218 | balrog | data[0] = 1; |
294 | a7954218 | balrog | ret = 1;
|
295 | a7954218 | balrog | break;
|
296 | a7954218 | balrog | case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
297 | a7954218 | balrog | ret = 0;
|
298 | a7954218 | balrog | break;
|
299 | a7954218 | balrog | case DeviceRequest | USB_REQ_GET_INTERFACE:
|
300 | a7954218 | balrog | data[0] = 0; |
301 | a7954218 | balrog | ret = 1;
|
302 | a7954218 | balrog | break;
|
303 | a7954218 | balrog | case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
304 | a7954218 | balrog | ret = 0;
|
305 | a7954218 | balrog | break;
|
306 | a7954218 | balrog | case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
307 | a7954218 | balrog | ret = 0;
|
308 | a7954218 | balrog | break;
|
309 | a7954218 | balrog | |
310 | a7954218 | balrog | /* Class specific requests. */
|
311 | a7954218 | balrog | case DeviceOutVendor | FTDI_RESET:
|
312 | a7954218 | balrog | switch (value) {
|
313 | a7954218 | balrog | case FTDI_RESET_SIO:
|
314 | a7954218 | balrog | usb_serial_reset(s); |
315 | a7954218 | balrog | break;
|
316 | a7954218 | balrog | case FTDI_RESET_RX:
|
317 | a7954218 | balrog | s->recv_ptr = 0;
|
318 | a7954218 | balrog | s->recv_used = 0;
|
319 | a7954218 | balrog | /* TODO: purge from char device */
|
320 | a7954218 | balrog | break;
|
321 | a7954218 | balrog | case FTDI_RESET_TX:
|
322 | a7954218 | balrog | /* TODO: purge from char device */
|
323 | a7954218 | balrog | break;
|
324 | a7954218 | balrog | } |
325 | a7954218 | balrog | break;
|
326 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_MDM_CTRL:
|
327 | abb8a139 | aurel32 | { |
328 | abb8a139 | aurel32 | static int flags; |
329 | abb8a139 | aurel32 | qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); |
330 | abb8a139 | aurel32 | if (value & FTDI_SET_RTS) {
|
331 | abb8a139 | aurel32 | if (value & FTDI_RTS)
|
332 | abb8a139 | aurel32 | flags |= CHR_TIOCM_RTS; |
333 | abb8a139 | aurel32 | else
|
334 | abb8a139 | aurel32 | flags &= ~CHR_TIOCM_RTS; |
335 | abb8a139 | aurel32 | } |
336 | abb8a139 | aurel32 | if (value & FTDI_SET_DTR) {
|
337 | abb8a139 | aurel32 | if (value & FTDI_DTR)
|
338 | abb8a139 | aurel32 | flags |= CHR_TIOCM_DTR; |
339 | abb8a139 | aurel32 | else
|
340 | abb8a139 | aurel32 | flags &= ~CHR_TIOCM_DTR; |
341 | abb8a139 | aurel32 | } |
342 | abb8a139 | aurel32 | qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); |
343 | a7954218 | balrog | break;
|
344 | abb8a139 | aurel32 | } |
345 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
|
346 | a7954218 | balrog | /* TODO: ioctl */
|
347 | a7954218 | balrog | break;
|
348 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_BAUD: {
|
349 | a7954218 | balrog | static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; |
350 | a7954218 | balrog | int subdivisor8 = subdivisors8[((value & 0xc000) >> 14) |
351 | a7954218 | balrog | | ((index & 1) << 2)]; |
352 | a7954218 | balrog | int divisor = value & 0x3fff; |
353 | a7954218 | balrog | |
354 | a7954218 | balrog | /* chip special cases */
|
355 | a7954218 | balrog | if (divisor == 1 && subdivisor8 == 0) |
356 | a7954218 | balrog | subdivisor8 = 4;
|
357 | a7954218 | balrog | if (divisor == 0 && subdivisor8 == 0) |
358 | a7954218 | balrog | divisor = 1;
|
359 | a7954218 | balrog | |
360 | a7954218 | balrog | s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8); |
361 | a7954218 | balrog | qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); |
362 | a7954218 | balrog | break;
|
363 | a7954218 | balrog | } |
364 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_DATA:
|
365 | a7954218 | balrog | switch (value & FTDI_PARITY) {
|
366 | a7954218 | balrog | case 0: |
367 | a7954218 | balrog | s->params.parity = 'N';
|
368 | a7954218 | balrog | break;
|
369 | a7954218 | balrog | case FTDI_ODD:
|
370 | a7954218 | balrog | s->params.parity = 'O';
|
371 | a7954218 | balrog | break;
|
372 | a7954218 | balrog | case FTDI_EVEN:
|
373 | a7954218 | balrog | s->params.parity = 'E';
|
374 | a7954218 | balrog | break;
|
375 | a7954218 | balrog | default:
|
376 | a7954218 | balrog | DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
|
377 | a7954218 | balrog | goto fail;
|
378 | a7954218 | balrog | } |
379 | a7954218 | balrog | switch (value & FTDI_STOP) {
|
380 | a7954218 | balrog | case FTDI_STOP1:
|
381 | a7954218 | balrog | s->params.stop_bits = 1;
|
382 | a7954218 | balrog | break;
|
383 | a7954218 | balrog | case FTDI_STOP2:
|
384 | a7954218 | balrog | s->params.stop_bits = 2;
|
385 | a7954218 | balrog | break;
|
386 | a7954218 | balrog | default:
|
387 | a7954218 | balrog | DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
|
388 | a7954218 | balrog | goto fail;
|
389 | a7954218 | balrog | } |
390 | a7954218 | balrog | qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); |
391 | a7954218 | balrog | /* TODO: TX ON/OFF */
|
392 | a7954218 | balrog | break;
|
393 | a7954218 | balrog | case DeviceInVendor | FTDI_GET_MDM_ST:
|
394 | abb8a139 | aurel32 | data[0] = usb_get_modem_lines(s) | 1; |
395 | abb8a139 | aurel32 | data[1] = 0; |
396 | abb8a139 | aurel32 | ret = 2;
|
397 | a7954218 | balrog | break;
|
398 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_EVENT_CHR:
|
399 | a7954218 | balrog | /* TODO: handle it */
|
400 | a7954218 | balrog | s->event_chr = value; |
401 | a7954218 | balrog | break;
|
402 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_ERROR_CHR:
|
403 | a7954218 | balrog | /* TODO: handle it */
|
404 | a7954218 | balrog | s->error_chr = value; |
405 | a7954218 | balrog | break;
|
406 | a7954218 | balrog | case DeviceOutVendor | FTDI_SET_LATENCY:
|
407 | a7954218 | balrog | s->latency = value; |
408 | a7954218 | balrog | break;
|
409 | a7954218 | balrog | case DeviceInVendor | FTDI_GET_LATENCY:
|
410 | a7954218 | balrog | data[0] = s->latency;
|
411 | a7954218 | balrog | ret = 1;
|
412 | a7954218 | balrog | break;
|
413 | a7954218 | balrog | default:
|
414 | a7954218 | balrog | fail:
|
415 | a7954218 | balrog | DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
|
416 | a7954218 | balrog | ret = USB_RET_STALL; |
417 | a7954218 | balrog | break;
|
418 | a7954218 | balrog | } |
419 | a7954218 | balrog | return ret;
|
420 | a7954218 | balrog | } |
421 | a7954218 | balrog | |
422 | a7954218 | balrog | static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) |
423 | a7954218 | balrog | { |
424 | a7954218 | balrog | USBSerialState *s = (USBSerialState *)dev; |
425 | a7954218 | balrog | int ret = 0; |
426 | a7954218 | balrog | uint8_t devep = p->devep; |
427 | a7954218 | balrog | uint8_t *data = p->data; |
428 | a7954218 | balrog | int len = p->len;
|
429 | a7954218 | balrog | int first_len;
|
430 | a7954218 | balrog | |
431 | a7954218 | balrog | switch (p->pid) {
|
432 | a7954218 | balrog | case USB_TOKEN_OUT:
|
433 | a7954218 | balrog | if (devep != 2) |
434 | a7954218 | balrog | goto fail;
|
435 | a7954218 | balrog | qemu_chr_write(s->cs, data, len); |
436 | a7954218 | balrog | break;
|
437 | a7954218 | balrog | |
438 | a7954218 | balrog | case USB_TOKEN_IN:
|
439 | a7954218 | balrog | if (devep != 1) |
440 | a7954218 | balrog | goto fail;
|
441 | a7954218 | balrog | first_len = RECV_BUF - s->recv_ptr; |
442 | a7954218 | balrog | if (len <= 2) { |
443 | a7954218 | balrog | ret = USB_RET_NAK; |
444 | a7954218 | balrog | break;
|
445 | a7954218 | balrog | } |
446 | abb8a139 | aurel32 | *data++ = usb_get_modem_lines(s) | 1;
|
447 | abb8a139 | aurel32 | /* We do not have the uart details */
|
448 | a7954218 | balrog | *data++ = 0;
|
449 | a7954218 | balrog | len -= 2;
|
450 | a7954218 | balrog | if (len > s->recv_used)
|
451 | a7954218 | balrog | len = s->recv_used; |
452 | a7954218 | balrog | if (!len) {
|
453 | a7954218 | balrog | ret = USB_RET_NAK; |
454 | a7954218 | balrog | break;
|
455 | a7954218 | balrog | } |
456 | a7954218 | balrog | if (first_len > len)
|
457 | a7954218 | balrog | first_len = len; |
458 | a7954218 | balrog | memcpy(data, s->recv_buf + s->recv_ptr, first_len); |
459 | a7954218 | balrog | if (len > first_len)
|
460 | a7954218 | balrog | memcpy(data + first_len, s->recv_buf, len - first_len); |
461 | a7954218 | balrog | s->recv_used -= len; |
462 | a7954218 | balrog | s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; |
463 | a7954218 | balrog | ret = len + 2;
|
464 | a7954218 | balrog | break;
|
465 | a7954218 | balrog | |
466 | a7954218 | balrog | default:
|
467 | a7954218 | balrog | DPRINTF("Bad token\n");
|
468 | a7954218 | balrog | fail:
|
469 | a7954218 | balrog | ret = USB_RET_STALL; |
470 | a7954218 | balrog | break;
|
471 | a7954218 | balrog | } |
472 | a7954218 | balrog | |
473 | a7954218 | balrog | return ret;
|
474 | a7954218 | balrog | } |
475 | a7954218 | balrog | |
476 | a7954218 | balrog | static void usb_serial_handle_destroy(USBDevice *dev) |
477 | a7954218 | balrog | { |
478 | a7954218 | balrog | USBSerialState *s = (USBSerialState *)dev; |
479 | a7954218 | balrog | |
480 | a7954218 | balrog | qemu_chr_close(s->cs); |
481 | a7954218 | balrog | qemu_free(s); |
482 | a7954218 | balrog | } |
483 | a7954218 | balrog | |
484 | 8fcd3692 | blueswir1 | static int usb_serial_can_read(void *opaque) |
485 | a7954218 | balrog | { |
486 | a7954218 | balrog | USBSerialState *s = opaque; |
487 | a7954218 | balrog | return RECV_BUF - s->recv_used;
|
488 | a7954218 | balrog | } |
489 | a7954218 | balrog | |
490 | 8fcd3692 | blueswir1 | static void usb_serial_read(void *opaque, const uint8_t *buf, int size) |
491 | a7954218 | balrog | { |
492 | a7954218 | balrog | USBSerialState *s = opaque; |
493 | a7954218 | balrog | int first_size = RECV_BUF - s->recv_ptr;
|
494 | a7954218 | balrog | if (first_size > size)
|
495 | a7954218 | balrog | first_size = size; |
496 | a7954218 | balrog | memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); |
497 | a7954218 | balrog | if (size > first_size)
|
498 | a7954218 | balrog | memcpy(s->recv_buf, buf + first_size, size - first_size); |
499 | a7954218 | balrog | s->recv_used += size; |
500 | a7954218 | balrog | } |
501 | a7954218 | balrog | |
502 | 8fcd3692 | blueswir1 | static void usb_serial_event(void *opaque, int event) |
503 | a7954218 | balrog | { |
504 | a7954218 | balrog | USBSerialState *s = opaque; |
505 | a7954218 | balrog | |
506 | a7954218 | balrog | switch (event) {
|
507 | a7954218 | balrog | case CHR_EVENT_BREAK:
|
508 | a7954218 | balrog | /* TODO: Send Break to USB */
|
509 | a7954218 | balrog | break;
|
510 | a7954218 | balrog | case CHR_EVENT_FOCUS:
|
511 | a7954218 | balrog | break;
|
512 | a7954218 | balrog | case CHR_EVENT_RESET:
|
513 | a7954218 | balrog | usb_serial_reset(s); |
514 | a7954218 | balrog | /* TODO: Reset USB port */
|
515 | a7954218 | balrog | break;
|
516 | a7954218 | balrog | } |
517 | a7954218 | balrog | } |
518 | a7954218 | balrog | |
519 | a7954218 | balrog | USBDevice *usb_serial_init(const char *filename) |
520 | a7954218 | balrog | { |
521 | a7954218 | balrog | USBSerialState *s; |
522 | a7954218 | balrog | CharDriverState *cdrv; |
523 | a11d070e | balrog | unsigned short vendorid = 0x0403, productid = 0x6001; |
524 | 5ccfae10 | aliguori | char label[32]; |
525 | 5ccfae10 | aliguori | static int index; |
526 | a7954218 | balrog | |
527 | a7954218 | balrog | while (*filename && *filename != ':') { |
528 | a7954218 | balrog | const char *p; |
529 | a7954218 | balrog | char *e;
|
530 | a7954218 | balrog | if (strstart(filename, "vendorid=", &p)) { |
531 | a7954218 | balrog | vendorid = strtol(p, &e, 16);
|
532 | a7954218 | balrog | if (e == p || (*e && *e != ',' && *e != ':')) { |
533 | a7954218 | balrog | printf("bogus vendor ID %s\n", p);
|
534 | a7954218 | balrog | return NULL; |
535 | a7954218 | balrog | } |
536 | a7954218 | balrog | filename = e; |
537 | a7954218 | balrog | } else if (strstart(filename, "productid=", &p)) { |
538 | a7954218 | balrog | productid = strtol(p, &e, 16);
|
539 | a7954218 | balrog | if (e == p || (*e && *e != ',' && *e != ':')) { |
540 | a7954218 | balrog | printf("bogus product ID %s\n", p);
|
541 | a7954218 | balrog | return NULL; |
542 | a7954218 | balrog | } |
543 | a7954218 | balrog | filename = e; |
544 | a7954218 | balrog | } else {
|
545 | a7954218 | balrog | printf("unrecognized serial USB option %s\n", filename);
|
546 | a7954218 | balrog | return NULL; |
547 | a7954218 | balrog | } |
548 | a7954218 | balrog | while(*filename == ',') |
549 | a7954218 | balrog | filename++; |
550 | a7954218 | balrog | } |
551 | a7954218 | balrog | if (!*filename) {
|
552 | a7954218 | balrog | printf("character device specification needed\n");
|
553 | a7954218 | balrog | return NULL; |
554 | a7954218 | balrog | } |
555 | a7954218 | balrog | filename++; |
556 | a7954218 | balrog | s = qemu_mallocz(sizeof(USBSerialState));
|
557 | a7954218 | balrog | if (!s)
|
558 | a7954218 | balrog | return NULL; |
559 | a7954218 | balrog | |
560 | 5ccfae10 | aliguori | snprintf(label, sizeof(label), "usbserial%d", index++); |
561 | 5ccfae10 | aliguori | cdrv = qemu_chr_open(label, filename); |
562 | a7954218 | balrog | if (!cdrv)
|
563 | a7954218 | balrog | goto fail;
|
564 | a7954218 | balrog | s->cs = cdrv; |
565 | a7954218 | balrog | qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s); |
566 | a7954218 | balrog | |
567 | a7954218 | balrog | s->dev.speed = USB_SPEED_FULL; |
568 | a7954218 | balrog | s->dev.handle_packet = usb_generic_handle_packet; |
569 | a7954218 | balrog | |
570 | a7954218 | balrog | s->dev.handle_reset = usb_serial_handle_reset; |
571 | a7954218 | balrog | s->dev.handle_control = usb_serial_handle_control; |
572 | a7954218 | balrog | s->dev.handle_data = usb_serial_handle_data; |
573 | a7954218 | balrog | s->dev.handle_destroy = usb_serial_handle_destroy; |
574 | a7954218 | balrog | |
575 | a7954218 | balrog | s->vendorid = vendorid; |
576 | a7954218 | balrog | s->productid = productid; |
577 | a7954218 | balrog | |
578 | a7954218 | balrog | snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)", |
579 | a7954218 | balrog | filename); |
580 | a7954218 | balrog | |
581 | a7954218 | balrog | usb_serial_handle_reset((USBDevice *)s); |
582 | a7954218 | balrog | return (USBDevice *)s;
|
583 | a7954218 | balrog | fail:
|
584 | a7954218 | balrog | qemu_free(s); |
585 | a7954218 | balrog | return NULL; |
586 | a7954218 | balrog | } |