diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-07 17:59:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-04-25 00:16:44 -0400 |
commit | 619a6f1d1423d08e74ed2b8a2113f12ef18e4373 (patch) | |
tree | 0e61a8c5bf85d27d72db244cc0ad49daa1ccaace /drivers/usb | |
parent | 7106967ecc0a33a7d7e2e04798eb9f45377f448b (diff) |
USB: add usb-serial spcp8x5 driver
Original version of the driver done by Linxb, changes by Harald, and
lots of cleanups by me in order to get it into a mergable state.
Cc: Linxb <xubin.lin@worldplus.com.cn>
Cc: Harald Klein <hari@vt100.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/Kconfig | 10 | ||||
-rw-r--r-- | drivers/usb/serial/Makefile | 3 | ||||
-rw-r--r-- | drivers/usb/serial/spcp8x5.c | 1075 |
3 files changed, 1087 insertions, 1 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index a769f6a5d7fb..f9c6c0922c00 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig | |||
@@ -503,6 +503,16 @@ config USB_SERIAL_OTI6858 | |||
503 | To compile this driver as a module, choose M here: the | 503 | To compile this driver as a module, choose M here: the |
504 | module will be called oti6858. | 504 | module will be called oti6858. |
505 | 505 | ||
506 | config USB_SERIAL_SPCP8X5 | ||
507 | tristate "USB SPCP8x5 USB To Serial Driver" | ||
508 | depends on USB_SERIAL | ||
509 | help | ||
510 | Say Y here if you want to use the spcp8x5 converter chip. This is | ||
511 | commonly found in some Z-Wave USB devices. | ||
512 | |||
513 | To compile this driver as a module, choose M here: the | ||
514 | module will be called spcp8x5. | ||
515 | |||
506 | config USB_SERIAL_HP4X | 516 | config USB_SERIAL_HP4X |
507 | tristate "USB HP4x Calculators support" | 517 | tristate "USB HP4x Calculators support" |
508 | depends on USB_SERIAL | 518 | depends on USB_SERIAL |
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 0db109a54d10..756859510d8c 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile | |||
@@ -30,8 +30,8 @@ obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o | |||
30 | obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o | 30 | obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o |
31 | obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o | 31 | obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o |
32 | obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o | 32 | obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o |
33 | obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o | ||
34 | obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o | 33 | obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o |
34 | obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o | ||
35 | obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o | 35 | obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o |
36 | obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o | 36 | obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o |
37 | obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o | 37 | obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o |
@@ -46,6 +46,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o | |||
46 | obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o | 46 | obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o |
47 | obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o | 47 | obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o |
48 | obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o | 48 | obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o |
49 | obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o | ||
49 | obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o | 50 | obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o |
50 | obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o | 51 | obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o |
51 | obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o | 52 | obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o |
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c new file mode 100644 index 000000000000..1b46b846f100 --- /dev/null +++ b/drivers/usb/serial/spcp8x5.c | |||
@@ -0,0 +1,1075 @@ | |||
1 | /* | ||
2 | * spcp8x5 USB to serial adaptor driver | ||
3 | * | ||
4 | * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) | ||
5 | * Copyright (C) 2006 S1 Corp. | ||
6 | * | ||
7 | * Original driver for 2.6.10 pl2303 driver by | ||
8 | * Greg Kroah-Hartman (greg@kroah.com) | ||
9 | * Changes for 2.6.20 by Harald Klein <hari@vt100.at> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/tty.h> | ||
23 | #include <linux/tty_driver.h> | ||
24 | #include <linux/tty_flip.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/usb.h> | ||
28 | #include <linux/usb/serial.h> | ||
29 | |||
30 | |||
31 | /* Version Information */ | ||
32 | #define DRIVER_VERSION "v0.04" | ||
33 | #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" | ||
34 | |||
35 | static int debug; | ||
36 | |||
37 | #define SPCP8x5_007_VID 0x04FC | ||
38 | #define SPCP8x5_007_PID 0x0201 | ||
39 | #define SPCP8x5_008_VID 0x04fc | ||
40 | #define SPCP8x5_008_PID 0x0235 | ||
41 | #define SPCP8x5_PHILIPS_VID 0x0471 | ||
42 | #define SPCP8x5_PHILIPS_PID 0x081e | ||
43 | #define SPCP8x5_INTERMATIC_VID 0x04FC | ||
44 | #define SPCP8x5_INTERMATIC_PID 0x0204 | ||
45 | #define SPCP8x5_835_VID 0x04fc | ||
46 | #define SPCP8x5_835_PID 0x0231 | ||
47 | |||
48 | static struct usb_device_id id_table [] = { | ||
49 | { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)}, | ||
50 | { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)}, | ||
51 | { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)}, | ||
52 | { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, | ||
53 | { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)}, | ||
54 | { } /* Terminating entry */ | ||
55 | }; | ||
56 | MODULE_DEVICE_TABLE(usb, id_table); | ||
57 | |||
58 | struct spcp8x5_usb_ctrl_arg { | ||
59 | u8 type; | ||
60 | u8 cmd; | ||
61 | u8 cmd_type; | ||
62 | u16 value; | ||
63 | u16 index; | ||
64 | u16 length; | ||
65 | }; | ||
66 | |||
67 | /* wait 30s before close */ | ||
68 | #define SPCP8x5_CLOSING_WAIT (30*HZ) | ||
69 | |||
70 | #define SPCP8x5_BUF_SIZE 1024 | ||
71 | |||
72 | |||
73 | /* spcp8x5 spec register define */ | ||
74 | #define MCR_CONTROL_LINE_RTS 0x02 | ||
75 | #define MCR_CONTROL_LINE_DTR 0x01 | ||
76 | #define MCR_DTR 0x01 | ||
77 | #define MCR_RTS 0x02 | ||
78 | |||
79 | #define MSR_STATUS_LINE_DCD 0x80 | ||
80 | #define MSR_STATUS_LINE_RI 0x40 | ||
81 | #define MSR_STATUS_LINE_DSR 0x20 | ||
82 | #define MSR_STATUS_LINE_CTS 0x10 | ||
83 | |||
84 | /* verdor command here , we should define myself */ | ||
85 | #define SET_DEFAULT 0x40 | ||
86 | #define SET_DEFAULT_TYPE 0x20 | ||
87 | |||
88 | #define SET_UART_FORMAT 0x40 | ||
89 | #define SET_UART_FORMAT_TYPE 0x21 | ||
90 | #define SET_UART_FORMAT_SIZE_5 0x00 | ||
91 | #define SET_UART_FORMAT_SIZE_6 0x01 | ||
92 | #define SET_UART_FORMAT_SIZE_7 0x02 | ||
93 | #define SET_UART_FORMAT_SIZE_8 0x03 | ||
94 | #define SET_UART_FORMAT_STOP_1 0x00 | ||
95 | #define SET_UART_FORMAT_STOP_2 0x04 | ||
96 | #define SET_UART_FORMAT_PAR_NONE 0x00 | ||
97 | #define SET_UART_FORMAT_PAR_ODD 0x10 | ||
98 | #define SET_UART_FORMAT_PAR_EVEN 0x30 | ||
99 | #define SET_UART_FORMAT_PAR_MASK 0xD0 | ||
100 | #define SET_UART_FORMAT_PAR_SPACE 0x90 | ||
101 | |||
102 | #define GET_UART_STATUS_TYPE 0xc0 | ||
103 | #define GET_UART_STATUS 0x22 | ||
104 | #define GET_UART_STATUS_MSR 0x06 | ||
105 | |||
106 | #define SET_UART_STATUS 0x40 | ||
107 | #define SET_UART_STATUS_TYPE 0x23 | ||
108 | #define SET_UART_STATUS_MCR 0x0004 | ||
109 | #define SET_UART_STATUS_MCR_DTR 0x01 | ||
110 | #define SET_UART_STATUS_MCR_RTS 0x02 | ||
111 | #define SET_UART_STATUS_MCR_LOOP 0x10 | ||
112 | |||
113 | #define SET_WORKING_MODE 0x40 | ||
114 | #define SET_WORKING_MODE_TYPE 0x24 | ||
115 | #define SET_WORKING_MODE_U2C 0x00 | ||
116 | #define SET_WORKING_MODE_RS485 0x01 | ||
117 | #define SET_WORKING_MODE_PDMA 0x02 | ||
118 | #define SET_WORKING_MODE_SPP 0x03 | ||
119 | |||
120 | #define SET_FLOWCTL_CHAR 0x40 | ||
121 | #define SET_FLOWCTL_CHAR_TYPE 0x25 | ||
122 | |||
123 | #define GET_VERSION 0xc0 | ||
124 | #define GET_VERSION_TYPE 0x26 | ||
125 | |||
126 | #define SET_REGISTER 0x40 | ||
127 | #define SET_REGISTER_TYPE 0x27 | ||
128 | |||
129 | #define GET_REGISTER 0xc0 | ||
130 | #define GET_REGISTER_TYPE 0x28 | ||
131 | |||
132 | #define SET_RAM 0x40 | ||
133 | #define SET_RAM_TYPE 0x31 | ||
134 | |||
135 | #define GET_RAM 0xc0 | ||
136 | #define GET_RAM_TYPE 0x32 | ||
137 | |||
138 | /* how come ??? */ | ||
139 | #define UART_STATE 0x08 | ||
140 | #define UART_STATE_TRANSIENT_MASK 0x74 | ||
141 | #define UART_DCD 0x01 | ||
142 | #define UART_DSR 0x02 | ||
143 | #define UART_BREAK_ERROR 0x04 | ||
144 | #define UART_RING 0x08 | ||
145 | #define UART_FRAME_ERROR 0x10 | ||
146 | #define UART_PARITY_ERROR 0x20 | ||
147 | #define UART_OVERRUN_ERROR 0x40 | ||
148 | #define UART_CTS 0x80 | ||
149 | |||
150 | enum spcp8x5_type { | ||
151 | SPCP825_007_TYPE, | ||
152 | SPCP825_008_TYPE, | ||
153 | SPCP825_PHILIP_TYPE, | ||
154 | SPCP825_INTERMATIC_TYPE, | ||
155 | SPCP835_TYPE, | ||
156 | }; | ||
157 | |||
158 | /* 1st in 1st out buffer 4 driver */ | ||
159 | struct ringbuf { | ||
160 | unsigned int buf_size; | ||
161 | char *buf_buf; | ||
162 | char *buf_get; | ||
163 | char *buf_put; | ||
164 | }; | ||
165 | |||
166 | /* alloc the ring buf and alloc the buffer itself */ | ||
167 | static inline struct ringbuf *alloc_ringbuf(unsigned int size) | ||
168 | { | ||
169 | struct ringbuf *pb; | ||
170 | |||
171 | if (size == 0) | ||
172 | return NULL; | ||
173 | |||
174 | pb = kmalloc(sizeof(*pb), GFP_KERNEL); | ||
175 | if (pb == NULL) | ||
176 | return NULL; | ||
177 | |||
178 | pb->buf_buf = kmalloc(size, GFP_KERNEL); | ||
179 | if (pb->buf_buf == NULL) { | ||
180 | kfree(pb); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | pb->buf_size = size; | ||
185 | pb->buf_get = pb->buf_put = pb->buf_buf; | ||
186 | |||
187 | return pb; | ||
188 | } | ||
189 | |||
190 | /* free the ring buf and the buffer itself */ | ||
191 | static inline void free_ringbuf(struct ringbuf *pb) | ||
192 | { | ||
193 | if (pb != NULL) { | ||
194 | kfree(pb->buf_buf); | ||
195 | kfree(pb); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* clear pipo , juest repoint the pointer here */ | ||
200 | static inline void clear_ringbuf(struct ringbuf *pb) | ||
201 | { | ||
202 | if (pb != NULL) | ||
203 | pb->buf_get = pb->buf_put; | ||
204 | } | ||
205 | |||
206 | /* get the number of data in the pipo */ | ||
207 | static inline unsigned int ringbuf_avail_data(struct ringbuf *pb) | ||
208 | { | ||
209 | if (pb == NULL) | ||
210 | return 0; | ||
211 | return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size); | ||
212 | } | ||
213 | |||
214 | /* get the number of space in the pipo */ | ||
215 | static inline unsigned int ringbuf_avail_space(struct ringbuf *pb) | ||
216 | { | ||
217 | if (pb == NULL) | ||
218 | return 0; | ||
219 | return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size); | ||
220 | } | ||
221 | |||
222 | /* put count data into pipo */ | ||
223 | static unsigned int put_ringbuf(struct ringbuf *pb, const char *buf, | ||
224 | unsigned int count) | ||
225 | { | ||
226 | unsigned int len; | ||
227 | |||
228 | if (pb == NULL) | ||
229 | return 0; | ||
230 | |||
231 | len = ringbuf_avail_space(pb); | ||
232 | if (count > len) | ||
233 | count = len; | ||
234 | |||
235 | if (count == 0) | ||
236 | return 0; | ||
237 | |||
238 | len = pb->buf_buf + pb->buf_size - pb->buf_put; | ||
239 | if (count > len) { | ||
240 | memcpy(pb->buf_put, buf, len); | ||
241 | memcpy(pb->buf_buf, buf+len, count - len); | ||
242 | pb->buf_put = pb->buf_buf + count - len; | ||
243 | } else { | ||
244 | memcpy(pb->buf_put, buf, count); | ||
245 | if (count < len) | ||
246 | pb->buf_put += count; | ||
247 | else /* count == len */ | ||
248 | pb->buf_put = pb->buf_buf; | ||
249 | } | ||
250 | return count; | ||
251 | } | ||
252 | |||
253 | /* get count data from pipo */ | ||
254 | static unsigned int get_ringbuf(struct ringbuf *pb, char *buf, | ||
255 | unsigned int count) | ||
256 | { | ||
257 | unsigned int len; | ||
258 | |||
259 | if (pb == NULL || buf == NULL) | ||
260 | return 0; | ||
261 | |||
262 | len = ringbuf_avail_data(pb); | ||
263 | if (count > len) | ||
264 | count = len; | ||
265 | |||
266 | if (count == 0) | ||
267 | return 0; | ||
268 | |||
269 | len = pb->buf_buf + pb->buf_size - pb->buf_get; | ||
270 | if (count > len) { | ||
271 | memcpy(buf, pb->buf_get, len); | ||
272 | memcpy(buf+len, pb->buf_buf, count - len); | ||
273 | pb->buf_get = pb->buf_buf + count - len; | ||
274 | } else { | ||
275 | memcpy(buf, pb->buf_get, count); | ||
276 | if (count < len) | ||
277 | pb->buf_get += count; | ||
278 | else /* count == len */ | ||
279 | pb->buf_get = pb->buf_buf; | ||
280 | } | ||
281 | |||
282 | return count; | ||
283 | } | ||
284 | |||
285 | static struct usb_driver spcp8x5_driver = { | ||
286 | .name = "spcp8x5", | ||
287 | .probe = usb_serial_probe, | ||
288 | .disconnect = usb_serial_disconnect, | ||
289 | .id_table = id_table, | ||
290 | .no_dynamic_id = 1, | ||
291 | }; | ||
292 | |||
293 | |||
294 | struct spcp8x5_private { | ||
295 | spinlock_t lock; | ||
296 | struct ringbuf *buf; | ||
297 | int write_urb_in_use; | ||
298 | enum spcp8x5_type type; | ||
299 | wait_queue_head_t delta_msr_wait; | ||
300 | u8 line_control; | ||
301 | u8 line_status; | ||
302 | u8 termios_initialized; | ||
303 | }; | ||
304 | |||
305 | /* desc : when device plug in,this function would be called. | ||
306 | * thanks to usb_serial subsystem,then do almost every things for us. And what | ||
307 | * we should do just alloc the buffer */ | ||
308 | static int spcp8x5_startup(struct usb_serial *serial) | ||
309 | { | ||
310 | struct spcp8x5_private *priv; | ||
311 | int i; | ||
312 | enum spcp8x5_type type = SPCP825_007_TYPE; | ||
313 | |||
314 | if (serial->dev->descriptor.idProduct == 0x0201) | ||
315 | type = SPCP825_007_TYPE; | ||
316 | else if (serial->dev->descriptor.idProduct == 0x0231) | ||
317 | type = SPCP835_TYPE; | ||
318 | else if (serial->dev->descriptor.idProduct == 0x0235) | ||
319 | type = SPCP825_008_TYPE; | ||
320 | else if (serial->dev->descriptor.idProduct == 0x0204) | ||
321 | type = SPCP825_INTERMATIC_TYPE; | ||
322 | else if (serial->dev->descriptor.idProduct == 0x0471 && | ||
323 | serial->dev->descriptor.idVendor == 0x081e) | ||
324 | type = SPCP825_PHILIP_TYPE; | ||
325 | dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); | ||
326 | |||
327 | for (i = 0; i < serial->num_ports; ++i) { | ||
328 | priv = kzalloc(sizeof(struct spcp8x5_private), GFP_KERNEL); | ||
329 | if (!priv) | ||
330 | goto cleanup; | ||
331 | |||
332 | spin_lock_init(&priv->lock); | ||
333 | priv->buf = alloc_ringbuf(SPCP8x5_BUF_SIZE); | ||
334 | if (priv->buf == NULL) | ||
335 | goto cleanup2; | ||
336 | |||
337 | init_waitqueue_head(&priv->delta_msr_wait); | ||
338 | priv->type = type; | ||
339 | usb_set_serial_port_data(serial->port[i] , priv); | ||
340 | |||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | |||
345 | cleanup2: | ||
346 | kfree(priv); | ||
347 | cleanup: | ||
348 | for (--i; i >= 0; --i) { | ||
349 | priv = usb_get_serial_port_data(serial->port[i]); | ||
350 | free_ringbuf(priv->buf); | ||
351 | kfree(priv); | ||
352 | usb_set_serial_port_data(serial->port[i] , NULL); | ||
353 | } | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | /* call when the device plug out. free all the memory alloced by probe */ | ||
358 | static void spcp8x5_shutdown(struct usb_serial *serial) | ||
359 | { | ||
360 | int i; | ||
361 | struct spcp8x5_private *priv; | ||
362 | |||
363 | for (i = 0; i < serial->num_ports; i++) { | ||
364 | priv = usb_get_serial_port_data(serial->port[i]); | ||
365 | if (priv) { | ||
366 | free_ringbuf(priv->buf); | ||
367 | kfree(priv); | ||
368 | usb_set_serial_port_data(serial->port[i] , NULL); | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | |||
373 | /* set the modem control line of the device. | ||
374 | * NOTE spcp825-007 not supported this */ | ||
375 | static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value, | ||
376 | enum spcp8x5_type type) | ||
377 | { | ||
378 | int retval; | ||
379 | u8 mcr = 0 ; | ||
380 | |||
381 | if (type == SPCP825_007_TYPE) | ||
382 | return -EPERM; | ||
383 | |||
384 | mcr = (unsigned short)value; | ||
385 | retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
386 | SET_UART_STATUS_TYPE, SET_UART_STATUS, | ||
387 | mcr, 0x04, NULL, 0, 100); | ||
388 | if (retval != 0) | ||
389 | dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval); | ||
390 | return retval; | ||
391 | } | ||
392 | |||
393 | /* get the modem status register of the device | ||
394 | * NOTE spcp825-007 not supported this */ | ||
395 | static int spcp8x5_get_msr(struct usb_device *dev, u8 *status, | ||
396 | enum spcp8x5_type type) | ||
397 | { | ||
398 | u8 *status_buffer; | ||
399 | int ret; | ||
400 | |||
401 | /* I return Permited not support here but seem inval device | ||
402 | * is more fix */ | ||
403 | if (type == SPCP825_007_TYPE) | ||
404 | return -EPERM; | ||
405 | if (status == NULL) | ||
406 | return -EINVAL; | ||
407 | |||
408 | status_buffer = kmalloc(1, GFP_KERNEL); | ||
409 | if (!status_buffer) | ||
410 | return -ENOMEM; | ||
411 | status_buffer[0] = status[0]; | ||
412 | |||
413 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
414 | GET_UART_STATUS, GET_UART_STATUS_TYPE, | ||
415 | 0, GET_UART_STATUS_MSR, status_buffer, 1, 100); | ||
416 | if (ret < 0) | ||
417 | dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", | ||
418 | status_buffer, ret); | ||
419 | |||
420 | dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer); | ||
421 | status[0] = status_buffer[0]; | ||
422 | kfree(status_buffer); | ||
423 | |||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | /* select the work mode. | ||
428 | * NOTE this function not supported by spcp825-007 */ | ||
429 | static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, | ||
430 | u16 index, enum spcp8x5_type type) | ||
431 | { | ||
432 | int ret; | ||
433 | |||
434 | /* I return Permited not support here but seem inval device | ||
435 | * is more fix */ | ||
436 | if (type == SPCP825_007_TYPE) | ||
437 | return; | ||
438 | |||
439 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
440 | SET_WORKING_MODE_TYPE, SET_WORKING_MODE, | ||
441 | value, index, NULL, 0, 100); | ||
442 | dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index); | ||
443 | if (ret < 0) | ||
444 | dev_dbg(&dev->dev, | ||
445 | "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); | ||
446 | } | ||
447 | |||
448 | /* close the serial port. We should wait for data sending to device 1st and | ||
449 | * then kill all urb. */ | ||
450 | static void spcp8x5_close(struct usb_serial_port *port, struct file *filp) | ||
451 | { | ||
452 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
453 | unsigned long flags; | ||
454 | unsigned int c_cflag; | ||
455 | int bps; | ||
456 | long timeout; | ||
457 | wait_queue_t wait; | ||
458 | int result; | ||
459 | |||
460 | dbg("%s - port %d", __func__, port->number); | ||
461 | |||
462 | /* wait for data to drain from the buffer */ | ||
463 | spin_lock_irqsave(&priv->lock, flags); | ||
464 | timeout = SPCP8x5_CLOSING_WAIT; | ||
465 | init_waitqueue_entry(&wait, current); | ||
466 | add_wait_queue(&port->tty->write_wait, &wait); | ||
467 | for (;;) { | ||
468 | set_current_state(TASK_INTERRUPTIBLE); | ||
469 | if (ringbuf_avail_data(priv->buf) == 0 || | ||
470 | timeout == 0 || signal_pending(current)) | ||
471 | break; | ||
472 | spin_unlock_irqrestore(&priv->lock, flags); | ||
473 | timeout = schedule_timeout(timeout); | ||
474 | spin_lock_irqsave(&priv->lock, flags); | ||
475 | } | ||
476 | set_current_state(TASK_RUNNING); | ||
477 | remove_wait_queue(&port->tty->write_wait, &wait); | ||
478 | |||
479 | /* clear out any remaining data in the buffer */ | ||
480 | clear_ringbuf(priv->buf); | ||
481 | spin_unlock_irqrestore(&priv->lock, flags); | ||
482 | |||
483 | /* wait for characters to drain from the device (this is long enough | ||
484 | * for the entire all byte spcp8x5 hardware buffer to drain with no | ||
485 | * flow control for data rates of 1200 bps or more, for lower rates we | ||
486 | * should really know how much data is in the buffer to compute a delay | ||
487 | * that is not unnecessarily long) */ | ||
488 | bps = tty_get_baud_rate(port->tty); | ||
489 | if (bps > 1200) | ||
490 | timeout = max((HZ*2560) / bps, HZ/10); | ||
491 | else | ||
492 | timeout = 2*HZ; | ||
493 | set_current_state(TASK_INTERRUPTIBLE); | ||
494 | schedule_timeout(timeout); | ||
495 | |||
496 | /* clear control lines */ | ||
497 | if (port->tty) { | ||
498 | c_cflag = port->tty->termios->c_cflag; | ||
499 | if (c_cflag & HUPCL) { | ||
500 | spin_lock_irqsave(&priv->lock, flags); | ||
501 | priv->line_control = 0; | ||
502 | spin_unlock_irqrestore(&priv->lock, flags); | ||
503 | spcp8x5_set_ctrlLine(port->serial->dev, 0 , priv->type); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* kill urb */ | ||
508 | if (port->write_urb != NULL) { | ||
509 | result = usb_unlink_urb(port->write_urb); | ||
510 | if (result) | ||
511 | dev_dbg(&port->dev, | ||
512 | "usb_unlink_urb(write_urb) = %d\n", result); | ||
513 | } | ||
514 | result = usb_unlink_urb(port->read_urb); | ||
515 | if (result) | ||
516 | dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result); | ||
517 | } | ||
518 | |||
519 | /* set the serial param for transfer. we should check if we really need to | ||
520 | * transfer. then if be set flow contorl we should do this too. */ | ||
521 | static void spcp8x5_set_termios(struct usb_serial_port *port, | ||
522 | struct ktermios *old_termios) | ||
523 | { | ||
524 | struct usb_serial *serial = port->serial; | ||
525 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
526 | unsigned long flags; | ||
527 | unsigned int cflag = port->tty->termios->c_cflag; | ||
528 | unsigned int old_cflag = old_termios->c_cflag; | ||
529 | unsigned short uartdata; | ||
530 | unsigned char buf[2] = {0, 0}; | ||
531 | int baud; | ||
532 | int i; | ||
533 | u8 control; | ||
534 | |||
535 | if ((!port->tty) || (!port->tty->termios)) | ||
536 | return; | ||
537 | |||
538 | /* for the 1st time call this function */ | ||
539 | spin_lock_irqsave(&priv->lock, flags); | ||
540 | if (!priv->termios_initialized) { | ||
541 | *(port->tty->termios) = tty_std_termios; | ||
542 | port->tty->termios->c_cflag = B115200 | CS8 | CREAD | | ||
543 | HUPCL | CLOCAL; | ||
544 | priv->termios_initialized = 1; | ||
545 | } | ||
546 | spin_unlock_irqrestore(&priv->lock, flags); | ||
547 | |||
548 | /* check that they really want us to change something */ | ||
549 | if (!tty_termios_hw_change(port->tty->termios, old_termios)) | ||
550 | return; | ||
551 | |||
552 | /* set DTR/RTS active */ | ||
553 | spin_lock_irqsave(&priv->lock, flags); | ||
554 | control = priv->line_control; | ||
555 | if ((old_cflag & CBAUD) == B0) { | ||
556 | priv->line_control |= MCR_DTR; | ||
557 | if (!(old_cflag & CRTSCTS)) | ||
558 | priv->line_control |= MCR_RTS; | ||
559 | } | ||
560 | if (control != priv->line_control) { | ||
561 | control = priv->line_control; | ||
562 | spin_unlock_irqrestore(&priv->lock, flags); | ||
563 | spcp8x5_set_ctrlLine(serial->dev, control , priv->type); | ||
564 | } else { | ||
565 | spin_unlock_irqrestore(&priv->lock, flags); | ||
566 | } | ||
567 | |||
568 | /* Set Baud Rate */ | ||
569 | baud = tty_get_baud_rate(port->tty);; | ||
570 | switch (baud) { | ||
571 | case 300: buf[0] = 0x00; break; | ||
572 | case 600: buf[0] = 0x01; break; | ||
573 | case 1200: buf[0] = 0x02; break; | ||
574 | case 2400: buf[0] = 0x03; break; | ||
575 | case 4800: buf[0] = 0x04; break; | ||
576 | case 9600: buf[0] = 0x05; break; | ||
577 | case 19200: buf[0] = 0x07; break; | ||
578 | case 38400: buf[0] = 0x09; break; | ||
579 | case 57600: buf[0] = 0x0a; break; | ||
580 | case 115200: buf[0] = 0x0b; break; | ||
581 | case 230400: buf[0] = 0x0c; break; | ||
582 | case 460800: buf[0] = 0x0d; break; | ||
583 | case 921600: buf[0] = 0x0e; break; | ||
584 | /* case 1200000: buf[0] = 0x0f; break; */ | ||
585 | /* case 2400000: buf[0] = 0x10; break; */ | ||
586 | case 3000000: buf[0] = 0x11; break; | ||
587 | /* case 6000000: buf[0] = 0x12; break; */ | ||
588 | case 0: | ||
589 | case 1000000: | ||
590 | buf[0] = 0x0b; break; | ||
591 | default: | ||
592 | err("spcp825 driver does not support the baudrate " | ||
593 | "requested, using default of 9600."); | ||
594 | } | ||
595 | |||
596 | /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ | ||
597 | if (cflag & CSIZE) { | ||
598 | switch (cflag & CSIZE) { | ||
599 | case CS5: | ||
600 | buf[1] |= SET_UART_FORMAT_SIZE_5; | ||
601 | break; | ||
602 | case CS6: | ||
603 | buf[1] |= SET_UART_FORMAT_SIZE_6; | ||
604 | break; | ||
605 | case CS7: | ||
606 | buf[1] |= SET_UART_FORMAT_SIZE_7; | ||
607 | break; | ||
608 | default: | ||
609 | case CS8: | ||
610 | buf[1] |= SET_UART_FORMAT_SIZE_8; | ||
611 | break; | ||
612 | } | ||
613 | } | ||
614 | |||
615 | /* Set Stop bit2 : 0:1bit 1:2bit */ | ||
616 | buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 : | ||
617 | SET_UART_FORMAT_STOP_1; | ||
618 | |||
619 | /* Set Parity bit3-4 01:Odd 11:Even */ | ||
620 | if (cflag & PARENB) { | ||
621 | buf[1] |= (cflag & PARODD) ? | ||
622 | SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; | ||
623 | } else | ||
624 | buf[1] |= SET_UART_FORMAT_PAR_NONE; | ||
625 | |||
626 | uartdata = buf[0] | buf[1]<<8; | ||
627 | |||
628 | i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
629 | SET_UART_FORMAT_TYPE, SET_UART_FORMAT, | ||
630 | uartdata, 0, NULL, 0, 100); | ||
631 | if (i < 0) | ||
632 | err("Set UART format %#x failed (error = %d)", uartdata, i); | ||
633 | dbg("0x21:0x40:0:0 %d\n", i); | ||
634 | |||
635 | if (cflag & CRTSCTS) { | ||
636 | /* enable hardware flow control */ | ||
637 | spcp8x5_set_workMode(serial->dev, 0x000a, | ||
638 | SET_WORKING_MODE_U2C, priv->type); | ||
639 | } | ||
640 | return; | ||
641 | } | ||
642 | |||
643 | /* open the serial port. do some usb system call. set termios and get the line | ||
644 | * status of the device. then submit the read urb */ | ||
645 | static int spcp8x5_open(struct usb_serial_port *port, struct file *filp) | ||
646 | { | ||
647 | struct ktermios tmp_termios; | ||
648 | struct usb_serial *serial = port->serial; | ||
649 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
650 | int ret; | ||
651 | unsigned long flags; | ||
652 | u8 status = 0x30; | ||
653 | /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ | ||
654 | |||
655 | dbg("%s - port %d", __func__, port->number); | ||
656 | |||
657 | usb_clear_halt(serial->dev, port->write_urb->pipe); | ||
658 | usb_clear_halt(serial->dev, port->read_urb->pipe); | ||
659 | |||
660 | ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
661 | 0x09, 0x00, | ||
662 | 0x01, 0x00, NULL, 0x00, 100); | ||
663 | if (ret) | ||
664 | return ret; | ||
665 | |||
666 | spin_lock_irqsave(&priv->lock, flags); | ||
667 | if (port->tty->termios->c_cflag & CBAUD) | ||
668 | priv->line_control = MCR_DTR | MCR_RTS; | ||
669 | else | ||
670 | priv->line_control = 0; | ||
671 | spin_unlock_irqrestore(&priv->lock, flags); | ||
672 | |||
673 | spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); | ||
674 | |||
675 | /* Setup termios */ | ||
676 | if (port->tty) | ||
677 | spcp8x5_set_termios(port, &tmp_termios); | ||
678 | |||
679 | spcp8x5_get_msr(serial->dev, &status, priv->type); | ||
680 | |||
681 | /* may be we should update uart status here but now we did not do */ | ||
682 | spin_lock_irqsave(&priv->lock, flags); | ||
683 | priv->line_status = status & 0xf0 ; | ||
684 | spin_unlock_irqrestore(&priv->lock, flags); | ||
685 | |||
686 | /* FIXME: need to assert RTS and DTR if CRTSCTS off */ | ||
687 | |||
688 | dbg("%s - submitting read urb", __func__); | ||
689 | port->read_urb->dev = serial->dev; | ||
690 | ret = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
691 | if (ret) { | ||
692 | spcp8x5_close(port, NULL); | ||
693 | return -EPROTO; | ||
694 | } | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | /* bulk read call back function. check the status of the urb. if transfer | ||
699 | * failed return. then update the status and the tty send data to tty subsys. | ||
700 | * submit urb again. | ||
701 | */ | ||
702 | static void spcp8x5_read_bulk_callback(struct urb *urb) | ||
703 | { | ||
704 | struct usb_serial_port *port = urb->context; | ||
705 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
706 | struct tty_struct *tty; | ||
707 | unsigned char *data = urb->transfer_buffer; | ||
708 | unsigned long flags; | ||
709 | int i; | ||
710 | int result; | ||
711 | u8 status = 0; | ||
712 | char tty_flag; | ||
713 | |||
714 | dev_dbg(&port->dev, "start, urb->status = %d, " | ||
715 | "urb->actual_length = %d\n,", urb->status, urb->actual_length); | ||
716 | |||
717 | /* check the urb status */ | ||
718 | if (urb->status) { | ||
719 | if (!port->open_count) | ||
720 | return; | ||
721 | if (urb->status == -EPROTO) { | ||
722 | /* spcp8x5 mysteriously fails with -EPROTO */ | ||
723 | /* reschedule the read */ | ||
724 | urb->status = 0; | ||
725 | urb->dev = port->serial->dev; | ||
726 | result = usb_submit_urb(urb , GFP_ATOMIC); | ||
727 | if (result) | ||
728 | dev_dbg(&port->dev, | ||
729 | "failed submitting read urb %d\n", | ||
730 | result); | ||
731 | return; | ||
732 | } | ||
733 | dev_dbg(&port->dev, "unable to handle the error, exiting.\n"); | ||
734 | return; | ||
735 | } | ||
736 | |||
737 | /* get tty_flag from status */ | ||
738 | tty_flag = TTY_NORMAL; | ||
739 | |||
740 | spin_lock_irqsave(&priv->lock, flags); | ||
741 | status = priv->line_status; | ||
742 | priv->line_status &= ~UART_STATE_TRANSIENT_MASK; | ||
743 | spin_unlock_irqrestore(&priv->lock, flags); | ||
744 | /* wake up the wait for termios */ | ||
745 | wake_up_interruptible(&priv->delta_msr_wait); | ||
746 | |||
747 | /* break takes precedence over parity, which takes precedence over | ||
748 | * framing errors */ | ||
749 | if (status & UART_BREAK_ERROR) | ||
750 | tty_flag = TTY_BREAK; | ||
751 | else if (status & UART_PARITY_ERROR) | ||
752 | tty_flag = TTY_PARITY; | ||
753 | else if (status & UART_FRAME_ERROR) | ||
754 | tty_flag = TTY_FRAME; | ||
755 | dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); | ||
756 | |||
757 | tty = port->tty; | ||
758 | if (tty && urb->actual_length) { | ||
759 | tty_buffer_request_room(tty, urb->actual_length + 1); | ||
760 | /* overrun is special, not associated with a char */ | ||
761 | if (status & UART_OVERRUN_ERROR) | ||
762 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
763 | for (i = 0; i < urb->actual_length; ++i) | ||
764 | tty_insert_flip_char(tty, data[i], tty_flag); | ||
765 | tty_flip_buffer_push(tty); | ||
766 | } | ||
767 | |||
768 | /* Schedule the next read _if_ we are still open */ | ||
769 | if (port->open_count) { | ||
770 | urb->dev = port->serial->dev; | ||
771 | result = usb_submit_urb(urb , GFP_ATOMIC); | ||
772 | if (result) | ||
773 | dev_dbg(&port->dev, "failed submitting read urb %d\n", | ||
774 | result); | ||
775 | } | ||
776 | |||
777 | return; | ||
778 | } | ||
779 | |||
780 | /* get data from ring buffer and then write to usb bus */ | ||
781 | static void spcp8x5_send(struct usb_serial_port *port) | ||
782 | { | ||
783 | int count, result; | ||
784 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
785 | unsigned long flags; | ||
786 | |||
787 | spin_lock_irqsave(&priv->lock, flags); | ||
788 | |||
789 | if (priv->write_urb_in_use) { | ||
790 | dev_dbg(&port->dev, "write urb still used\n"); | ||
791 | spin_unlock_irqrestore(&priv->lock, flags); | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | /* send the 1st urb for writting */ | ||
796 | memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size); | ||
797 | count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer, | ||
798 | port->bulk_out_size); | ||
799 | |||
800 | if (count == 0) { | ||
801 | spin_unlock_irqrestore(&priv->lock, flags); | ||
802 | return; | ||
803 | } | ||
804 | |||
805 | /* update the urb status */ | ||
806 | priv->write_urb_in_use = 1; | ||
807 | |||
808 | spin_unlock_irqrestore(&priv->lock, flags); | ||
809 | |||
810 | port->write_urb->transfer_buffer_length = count; | ||
811 | port->write_urb->dev = port->serial->dev; | ||
812 | |||
813 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); | ||
814 | if (result) { | ||
815 | dev_dbg(&port->dev, "failed submitting write urb, error %d\n", | ||
816 | result); | ||
817 | priv->write_urb_in_use = 0; | ||
818 | /* TODO: reschedule spcp8x5_send */ | ||
819 | } | ||
820 | |||
821 | |||
822 | schedule_work(&port->work); | ||
823 | } | ||
824 | |||
825 | /* this is the call back function for write urb. NOTE we should not sleep in | ||
826 | * this routine. check the urb return code and then submit the write urb again | ||
827 | * to hold the write loop */ | ||
828 | static void spcp8x5_write_bulk_callback(struct urb *urb) | ||
829 | { | ||
830 | struct usb_serial_port *port = urb->context; | ||
831 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
832 | int result; | ||
833 | |||
834 | switch (urb->status) { | ||
835 | case 0: | ||
836 | /* success */ | ||
837 | break; | ||
838 | case -ECONNRESET: | ||
839 | case -ENOENT: | ||
840 | case -ESHUTDOWN: | ||
841 | /* this urb is terminated, clean up */ | ||
842 | dev_dbg(&port->dev, "urb shutting down with status: %d\n", | ||
843 | urb->status); | ||
844 | priv->write_urb_in_use = 0; | ||
845 | return; | ||
846 | default: | ||
847 | /* error in the urb, so we have to resubmit it */ | ||
848 | dbg("%s - Overflow in write", __func__); | ||
849 | dbg("%s - nonzero write bulk status received: %d", | ||
850 | __func__, urb->status); | ||
851 | port->write_urb->transfer_buffer_length = 1; | ||
852 | port->write_urb->dev = port->serial->dev; | ||
853 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); | ||
854 | if (result) | ||
855 | dev_dbg(&port->dev, | ||
856 | "failed resubmitting write urb %d\n", result); | ||
857 | else | ||
858 | return; | ||
859 | } | ||
860 | |||
861 | priv->write_urb_in_use = 0; | ||
862 | |||
863 | /* send any buffered data */ | ||
864 | spcp8x5_send(port); | ||
865 | } | ||
866 | |||
867 | /* write data to ring buffer. and then start the write transfer */ | ||
868 | static int spcp8x5_write(struct usb_serial_port *port, | ||
869 | const unsigned char *buf, int count) | ||
870 | { | ||
871 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
872 | unsigned long flags; | ||
873 | |||
874 | dev_dbg(&port->dev, "%d bytes\n", count); | ||
875 | |||
876 | if (!count) | ||
877 | return count; | ||
878 | |||
879 | spin_lock_irqsave(&priv->lock, flags); | ||
880 | count = put_ringbuf(priv->buf, buf, count); | ||
881 | spin_unlock_irqrestore(&priv->lock, flags); | ||
882 | |||
883 | spcp8x5_send(port); | ||
884 | |||
885 | return count; | ||
886 | } | ||
887 | |||
888 | static int spcp8x5_wait_modem_info(struct usb_serial_port *port, | ||
889 | unsigned int arg) | ||
890 | { | ||
891 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
892 | unsigned long flags; | ||
893 | unsigned int prevstatus; | ||
894 | unsigned int status; | ||
895 | unsigned int changed; | ||
896 | |||
897 | spin_lock_irqsave(&priv->lock, flags); | ||
898 | prevstatus = priv->line_status; | ||
899 | spin_unlock_irqrestore(&priv->lock, flags); | ||
900 | |||
901 | while (1) { | ||
902 | /* wake up in bulk read */ | ||
903 | interruptible_sleep_on(&priv->delta_msr_wait); | ||
904 | |||
905 | /* see if a signal did it */ | ||
906 | if (signal_pending(current)) | ||
907 | return -ERESTARTSYS; | ||
908 | |||
909 | spin_lock_irqsave(&priv->lock, flags); | ||
910 | status = priv->line_status; | ||
911 | spin_unlock_irqrestore(&priv->lock, flags); | ||
912 | |||
913 | changed = prevstatus^status; | ||
914 | |||
915 | if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) || | ||
916 | ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) || | ||
917 | ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) || | ||
918 | ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS))) | ||
919 | return 0; | ||
920 | |||
921 | prevstatus = status; | ||
922 | } | ||
923 | /* NOTREACHED */ | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int spcp8x5_ioctl(struct usb_serial_port *port, struct file *file, | ||
928 | unsigned int cmd, unsigned long arg) | ||
929 | { | ||
930 | dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); | ||
931 | |||
932 | switch (cmd) { | ||
933 | case TIOCMIWAIT: | ||
934 | dbg("%s (%d) TIOCMIWAIT", __func__, port->number); | ||
935 | return spcp8x5_wait_modem_info(port, arg); | ||
936 | |||
937 | default: | ||
938 | dbg("%s not supported = 0x%04x", __func__, cmd); | ||
939 | break; | ||
940 | } | ||
941 | |||
942 | return -ENOIOCTLCMD; | ||
943 | } | ||
944 | |||
945 | static int spcp8x5_tiocmset(struct usb_serial_port *port, struct file *file, | ||
946 | unsigned int set, unsigned int clear) | ||
947 | { | ||
948 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
949 | unsigned long flags; | ||
950 | u8 control; | ||
951 | |||
952 | spin_lock_irqsave(&priv->lock, flags); | ||
953 | if (set & TIOCM_RTS) | ||
954 | priv->line_control |= MCR_RTS; | ||
955 | if (set & TIOCM_DTR) | ||
956 | priv->line_control |= MCR_DTR; | ||
957 | if (clear & TIOCM_RTS) | ||
958 | priv->line_control &= ~MCR_RTS; | ||
959 | if (clear & TIOCM_DTR) | ||
960 | priv->line_control &= ~MCR_DTR; | ||
961 | control = priv->line_control; | ||
962 | spin_unlock_irqrestore(&priv->lock, flags); | ||
963 | |||
964 | return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); | ||
965 | } | ||
966 | |||
967 | static int spcp8x5_tiocmget(struct usb_serial_port *port, struct file *file) | ||
968 | { | ||
969 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
970 | unsigned long flags; | ||
971 | unsigned int mcr; | ||
972 | unsigned int status; | ||
973 | unsigned int result; | ||
974 | |||
975 | spin_lock_irqsave(&priv->lock, flags); | ||
976 | mcr = priv->line_control; | ||
977 | status = priv->line_status; | ||
978 | spin_unlock_irqrestore(&priv->lock, flags); | ||
979 | |||
980 | result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | ||
981 | | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | ||
982 | | ((status & MSR_STATUS_LINE_CTS) ? TIOCM_CTS : 0) | ||
983 | | ((status & MSR_STATUS_LINE_DSR) ? TIOCM_DSR : 0) | ||
984 | | ((status & MSR_STATUS_LINE_RI) ? TIOCM_RI : 0) | ||
985 | | ((status & MSR_STATUS_LINE_DCD) ? TIOCM_CD : 0); | ||
986 | |||
987 | return result; | ||
988 | } | ||
989 | |||
990 | /* get the avail space room in ring buffer */ | ||
991 | static int spcp8x5_write_room(struct usb_serial_port *port) | ||
992 | { | ||
993 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
994 | int room = 0; | ||
995 | unsigned long flags; | ||
996 | |||
997 | spin_lock_irqsave(&priv->lock, flags); | ||
998 | room = ringbuf_avail_space(priv->buf); | ||
999 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1000 | |||
1001 | return room; | ||
1002 | } | ||
1003 | |||
1004 | /* get the number of avail data in write ring buffer */ | ||
1005 | static int spcp8x5_chars_in_buffer(struct usb_serial_port *port) | ||
1006 | { | ||
1007 | struct spcp8x5_private *priv = usb_get_serial_port_data(port); | ||
1008 | int chars = 0; | ||
1009 | unsigned long flags; | ||
1010 | |||
1011 | spin_lock_irqsave(&priv->lock, flags); | ||
1012 | chars = ringbuf_avail_data(priv->buf); | ||
1013 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1014 | |||
1015 | return chars; | ||
1016 | } | ||
1017 | |||
1018 | /* All of the device info needed for the spcp8x5 SIO serial converter */ | ||
1019 | static struct usb_serial_driver spcp8x5_device = { | ||
1020 | .driver = { | ||
1021 | .owner = THIS_MODULE, | ||
1022 | .name = "SPCP8x5", | ||
1023 | }, | ||
1024 | .id_table = id_table, | ||
1025 | .num_interrupt_in = NUM_DONT_CARE, | ||
1026 | .num_bulk_in = 1, | ||
1027 | .num_bulk_out = 1, | ||
1028 | .num_ports = 1, | ||
1029 | .open = spcp8x5_open, | ||
1030 | .close = spcp8x5_close, | ||
1031 | .write = spcp8x5_write, | ||
1032 | .set_termios = spcp8x5_set_termios, | ||
1033 | .ioctl = spcp8x5_ioctl, | ||
1034 | .tiocmget = spcp8x5_tiocmget, | ||
1035 | .tiocmset = spcp8x5_tiocmset, | ||
1036 | .write_room = spcp8x5_write_room, | ||
1037 | .read_bulk_callback = spcp8x5_read_bulk_callback, | ||
1038 | .write_bulk_callback = spcp8x5_write_bulk_callback, | ||
1039 | .chars_in_buffer = spcp8x5_chars_in_buffer, | ||
1040 | .attach = spcp8x5_startup, | ||
1041 | .shutdown = spcp8x5_shutdown, | ||
1042 | }; | ||
1043 | |||
1044 | static int __init spcp8x5_init(void) | ||
1045 | { | ||
1046 | int retval; | ||
1047 | retval = usb_serial_register(&spcp8x5_device); | ||
1048 | if (retval) | ||
1049 | goto failed_usb_serial_register; | ||
1050 | retval = usb_register(&spcp8x5_driver); | ||
1051 | if (retval) | ||
1052 | goto failed_usb_register; | ||
1053 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
1054 | return 0; | ||
1055 | failed_usb_register: | ||
1056 | usb_serial_deregister(&spcp8x5_device); | ||
1057 | failed_usb_serial_register: | ||
1058 | return retval; | ||
1059 | } | ||
1060 | |||
1061 | static void __exit spcp8x5_exit(void) | ||
1062 | { | ||
1063 | usb_deregister(&spcp8x5_driver); | ||
1064 | usb_serial_deregister(&spcp8x5_device); | ||
1065 | } | ||
1066 | |||
1067 | module_init(spcp8x5_init); | ||
1068 | module_exit(spcp8x5_exit); | ||
1069 | |||
1070 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1071 | MODULE_VERSION(DRIVER_VERSION); | ||
1072 | MODULE_LICENSE("GPL"); | ||
1073 | |||
1074 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
1075 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||