aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/spcp8x5.c
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2010-05-15 11:53:47 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 16:21:48 -0400
commitfa993ca8641ba650c762ea6701b0333118430d8c (patch)
tree0627de12ced565508a2dc09078e66ba93495a897 /drivers/usb/serial/spcp8x5.c
parent6b6962f9c489ecfa43ae27eb798c46717e203322 (diff)
USB: spcp8x5: reimplement using generic framework
Kill custom fifo, read, and single-urb write implementations. Compile-only tested. Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/spcp8x5.c')
-rw-r--r--drivers/usb/serial/spcp8x5.c407
1 files changed, 29 insertions, 378 deletions
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 2ea32c561d02..329d311a35d9 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * spcp8x5 USB to serial adaptor driver 2 * spcp8x5 USB to serial adaptor driver
3 * 3 *
4 * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
4 * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) 5 * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
5 * Copyright (C) 2006 S1 Corp. 6 * Copyright (C) 2006 S1 Corp.
6 * 7 *
@@ -29,7 +30,7 @@
29 30
30 31
31/* Version Information */ 32/* Version Information */
32#define DRIVER_VERSION "v0.04" 33#define DRIVER_VERSION "v0.10"
33#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" 34#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
34 35
35static int debug; 36static int debug;
@@ -64,11 +65,6 @@ struct spcp8x5_usb_ctrl_arg {
64 u16 length; 65 u16 length;
65}; 66};
66 67
67/* wait 30s before close */
68#define SPCP8x5_CLOSING_WAIT (30*HZ)
69
70#define SPCP8x5_BUF_SIZE 1024
71
72 68
73/* spcp8x5 spec register define */ 69/* spcp8x5 spec register define */
74#define MCR_CONTROL_LINE_RTS 0x02 70#define MCR_CONTROL_LINE_RTS 0x02
@@ -155,133 +151,6 @@ enum spcp8x5_type {
155 SPCP835_TYPE, 151 SPCP835_TYPE,
156}; 152};
157 153
158/* 1st in 1st out buffer 4 driver */
159struct 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 */
167static 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 */
191static 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 */
200static 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 */
207static 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 */
215static 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 */
223static 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 */
254static 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
285static struct usb_driver spcp8x5_driver = { 154static struct usb_driver spcp8x5_driver = {
286 .name = "spcp8x5", 155 .name = "spcp8x5",
287 .probe = usb_serial_probe, 156 .probe = usb_serial_probe,
@@ -293,8 +162,6 @@ static struct usb_driver spcp8x5_driver = {
293 162
294struct spcp8x5_private { 163struct spcp8x5_private {
295 spinlock_t lock; 164 spinlock_t lock;
296 struct ringbuf *buf;
297 int write_urb_in_use;
298 enum spcp8x5_type type; 165 enum spcp8x5_type type;
299 wait_queue_head_t delta_msr_wait; 166 wait_queue_head_t delta_msr_wait;
300 u8 line_control; 167 u8 line_control;
@@ -330,24 +197,15 @@ static int spcp8x5_startup(struct usb_serial *serial)
330 goto cleanup; 197 goto cleanup;
331 198
332 spin_lock_init(&priv->lock); 199 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); 200 init_waitqueue_head(&priv->delta_msr_wait);
338 priv->type = type; 201 priv->type = type;
339 usb_set_serial_port_data(serial->port[i] , priv); 202 usb_set_serial_port_data(serial->port[i] , priv);
340
341 } 203 }
342 204
343 return 0; 205 return 0;
344
345cleanup2:
346 kfree(priv);
347cleanup: 206cleanup:
348 for (--i; i >= 0; --i) { 207 for (--i; i >= 0; --i) {
349 priv = usb_get_serial_port_data(serial->port[i]); 208 priv = usb_get_serial_port_data(serial->port[i]);
350 free_ringbuf(priv->buf);
351 kfree(priv); 209 kfree(priv);
352 usb_set_serial_port_data(serial->port[i] , NULL); 210 usb_set_serial_port_data(serial->port[i] , NULL);
353 } 211 }
@@ -358,15 +216,9 @@ cleanup:
358static void spcp8x5_release(struct usb_serial *serial) 216static void spcp8x5_release(struct usb_serial *serial)
359{ 217{
360 int i; 218 int i;
361 struct spcp8x5_private *priv;
362 219
363 for (i = 0; i < serial->num_ports; i++) { 220 for (i = 0; i < serial->num_ports; i++)
364 priv = usb_get_serial_port_data(serial->port[i]); 221 kfree(usb_get_serial_port_data(serial->port[i]));
365 if (priv) {
366 free_ringbuf(priv->buf);
367 kfree(priv);
368 }
369 }
370} 222}
371 223
372/* set the modem control line of the device. 224/* set the modem control line of the device.
@@ -470,33 +322,6 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
470 spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); 322 spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
471} 323}
472 324
473/* close the serial port. We should wait for data sending to device 1st and
474 * then kill all urb. */
475static void spcp8x5_close(struct usb_serial_port *port)
476{
477 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
478 unsigned long flags;
479 int result;
480
481 dbg("%s - port %d", __func__, port->number);
482
483 spin_lock_irqsave(&priv->lock, flags);
484 /* clear out any remaining data in the buffer */
485 clear_ringbuf(priv->buf);
486 spin_unlock_irqrestore(&priv->lock, flags);
487
488 /* kill urb */
489 if (port->write_urb != NULL) {
490 result = usb_unlink_urb(port->write_urb);
491 if (result)
492 dev_dbg(&port->dev,
493 "usb_unlink_urb(write_urb) = %d\n", result);
494 }
495 result = usb_unlink_urb(port->read_urb);
496 if (result)
497 dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
498}
499
500static void spcp8x5_init_termios(struct tty_struct *tty) 325static void spcp8x5_init_termios(struct tty_struct *tty)
501{ 326{
502 /* for the 1st time call this function */ 327 /* for the 1st time call this function */
@@ -620,7 +445,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
620} 445}
621 446
622/* open the serial port. do some usb system call. set termios and get the line 447/* open the serial port. do some usb system call. set termios and get the line
623 * status of the device. then submit the read urb */ 448 * status of the device. */
624static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) 449static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
625{ 450{
626 struct ktermios tmp_termios; 451 struct ktermios tmp_termios;
@@ -655,52 +480,21 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
655 priv->line_status = status & 0xf0 ; 480 priv->line_status = status & 0xf0 ;
656 spin_unlock_irqrestore(&priv->lock, flags); 481 spin_unlock_irqrestore(&priv->lock, flags);
657 482
658 dbg("%s - submitting read urb", __func__);
659 port->read_urb->dev = serial->dev;
660 ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
661 if (ret) {
662 spcp8x5_close(port);
663 return -EPROTO;
664 }
665 port->port.drain_delay = 256; 483 port->port.drain_delay = 256;
666 return 0; 484
485 return usb_serial_generic_open(tty, port);
667} 486}
668 487
669/* bulk read call back function. check the status of the urb. if transfer 488static void spcp8x5_process_read_urb(struct urb *urb)
670 * failed return. then update the status and the tty send data to tty subsys.
671 * submit urb again.
672 */
673static void spcp8x5_read_bulk_callback(struct urb *urb)
674{ 489{
675 struct usb_serial_port *port = urb->context; 490 struct usb_serial_port *port = urb->context;
676 struct spcp8x5_private *priv = usb_get_serial_port_data(port); 491 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
677 struct tty_struct *tty; 492 struct tty_struct *tty;
678 unsigned char *data = urb->transfer_buffer; 493 unsigned char *data = urb->transfer_buffer;
679 unsigned long flags; 494 unsigned long flags;
680 int result = urb->status;
681 u8 status; 495 u8 status;
682 char tty_flag; 496 char tty_flag;
683 497
684 dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,",
685 result, urb->actual_length);
686
687 /* check the urb status */
688 if (result) {
689 if (result == -EPROTO) {
690 /* spcp8x5 mysteriously fails with -EPROTO */
691 /* reschedule the read */
692 urb->dev = port->serial->dev;
693 result = usb_submit_urb(urb , GFP_ATOMIC);
694 if (result)
695 dev_dbg(&port->dev,
696 "failed submitting read urb %d\n",
697 result);
698 return;
699 }
700 dev_dbg(&port->dev, "unable to handle the error, exiting.\n");
701 return;
702 }
703
704 /* get tty_flag from status */ 498 /* get tty_flag from status */
705 tty_flag = TTY_NORMAL; 499 tty_flag = TTY_NORMAL;
706 500
@@ -711,141 +505,33 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
711 /* wake up the wait for termios */ 505 /* wake up the wait for termios */
712 wake_up_interruptible(&priv->delta_msr_wait); 506 wake_up_interruptible(&priv->delta_msr_wait);
713 507
714 /* break takes precedence over parity, which takes precedence over 508 if (!urb->actual_length)
715 * framing errors */
716 if (status & UART_BREAK_ERROR)
717 tty_flag = TTY_BREAK;
718 else if (status & UART_PARITY_ERROR)
719 tty_flag = TTY_PARITY;
720 else if (status & UART_FRAME_ERROR)
721 tty_flag = TTY_FRAME;
722 dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
723
724 tty = tty_port_tty_get(&port->port);
725 if (tty && urb->actual_length) {
726 /* overrun is special, not associated with a char */
727 if (status & UART_OVERRUN_ERROR)
728 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
729 tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
730 urb->actual_length);
731 tty_flip_buffer_push(tty);
732 }
733 tty_kref_put(tty);
734
735 /* Schedule the next read */
736 urb->dev = port->serial->dev;
737 result = usb_submit_urb(urb , GFP_ATOMIC);
738 if (result)
739 dev_dbg(&port->dev, "failed submitting read urb %d\n", result);
740}
741
742/* get data from ring buffer and then write to usb bus */
743static void spcp8x5_send(struct usb_serial_port *port)
744{
745 int count, result;
746 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
747 unsigned long flags;
748
749 spin_lock_irqsave(&priv->lock, flags);
750
751 if (priv->write_urb_in_use) {
752 dev_dbg(&port->dev, "write urb still used\n");
753 spin_unlock_irqrestore(&priv->lock, flags);
754 return; 509 return;
755 }
756
757 /* send the 1st urb for writting */
758 memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size);
759 count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer,
760 port->bulk_out_size);
761 510
762 if (count == 0) { 511 tty = tty_port_tty_get(&port->port);
763 spin_unlock_irqrestore(&priv->lock, flags); 512 if (!tty)
764 return; 513 return;
765 }
766
767 /* update the urb status */
768 priv->write_urb_in_use = 1;
769
770 spin_unlock_irqrestore(&priv->lock, flags);
771
772 port->write_urb->transfer_buffer_length = count;
773 port->write_urb->dev = port->serial->dev;
774
775 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
776 if (result) {
777 dev_dbg(&port->dev, "failed submitting write urb, error %d\n",
778 result);
779 priv->write_urb_in_use = 0;
780 /* TODO: reschedule spcp8x5_send */
781 }
782
783
784 schedule_work(&port->work);
785}
786 514
787/* this is the call back function for write urb. NOTE we should not sleep in 515 if (status & UART_STATE_TRANSIENT_MASK) {
788 * this routine. check the urb return code and then submit the write urb again 516 /* break takes precedence over parity, which takes precedence
789 * to hold the write loop */ 517 * over framing errors */
790static void spcp8x5_write_bulk_callback(struct urb *urb) 518 if (status & UART_BREAK_ERROR)
791{ 519 tty_flag = TTY_BREAK;
792 struct usb_serial_port *port = urb->context; 520 else if (status & UART_PARITY_ERROR)
793 struct spcp8x5_private *priv = usb_get_serial_port_data(port); 521 tty_flag = TTY_PARITY;
794 int result; 522 else if (status & UART_FRAME_ERROR)
795 int status = urb->status; 523 tty_flag = TTY_FRAME;
524 dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
796 525
797 switch (status) { 526 /* overrun is special, not associated with a char */
798 case 0: 527 if (status & UART_OVERRUN_ERROR)
799 /* success */ 528 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
800 break;
801 case -ECONNRESET:
802 case -ENOENT:
803 case -ESHUTDOWN:
804 /* this urb is terminated, clean up */
805 dev_dbg(&port->dev, "urb shutting down with status: %d\n",
806 status);
807 priv->write_urb_in_use = 0;
808 return;
809 default:
810 /* error in the urb, so we have to resubmit it */
811 dbg("%s - Overflow in write", __func__);
812 dbg("%s - nonzero write bulk status received: %d",
813 __func__, status);
814 port->write_urb->transfer_buffer_length = 1;
815 port->write_urb->dev = port->serial->dev;
816 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
817 if (result)
818 dev_dbg(&port->dev,
819 "failed resubmitting write urb %d\n", result);
820 else
821 return;
822 } 529 }
823 530
824 priv->write_urb_in_use = 0; 531 tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
825 532 urb->actual_length);
826 /* send any buffered data */ 533 tty_flip_buffer_push(tty);
827 spcp8x5_send(port); 534 tty_kref_put(tty);
828}
829
830/* write data to ring buffer. and then start the write transfer */
831static int spcp8x5_write(struct tty_struct *tty, struct usb_serial_port *port,
832 const unsigned char *buf, int count)
833{
834 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
835 unsigned long flags;
836
837 dev_dbg(&port->dev, "%d bytes\n", count);
838
839 if (!count)
840 return count;
841
842 spin_lock_irqsave(&priv->lock, flags);
843 count = put_ringbuf(priv->buf, buf, count);
844 spin_unlock_irqrestore(&priv->lock, flags);
845
846 spcp8x5_send(port);
847
848 return count;
849} 535}
850 536
851static int spcp8x5_wait_modem_info(struct usb_serial_port *port, 537static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
@@ -953,36 +639,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty, struct file *file)
953 return result; 639 return result;
954} 640}
955 641
956/* get the avail space room in ring buffer */
957static int spcp8x5_write_room(struct tty_struct *tty)
958{
959 struct usb_serial_port *port = tty->driver_data;
960 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
961 int room = 0;
962 unsigned long flags;
963
964 spin_lock_irqsave(&priv->lock, flags);
965 room = ringbuf_avail_space(priv->buf);
966 spin_unlock_irqrestore(&priv->lock, flags);
967
968 return room;
969}
970
971/* get the number of avail data in write ring buffer */
972static int spcp8x5_chars_in_buffer(struct tty_struct *tty)
973{
974 struct usb_serial_port *port = tty->driver_data;
975 struct spcp8x5_private *priv = usb_get_serial_port_data(port);
976 int chars = 0;
977 unsigned long flags;
978
979 spin_lock_irqsave(&priv->lock, flags);
980 chars = ringbuf_avail_data(priv->buf);
981 spin_unlock_irqrestore(&priv->lock, flags);
982
983 return chars;
984}
985
986/* All of the device info needed for the spcp8x5 SIO serial converter */ 642/* All of the device info needed for the spcp8x5 SIO serial converter */
987static struct usb_serial_driver spcp8x5_device = { 643static struct usb_serial_driver spcp8x5_device = {
988 .driver = { 644 .driver = {
@@ -992,21 +648,16 @@ static struct usb_serial_driver spcp8x5_device = {
992 .id_table = id_table, 648 .id_table = id_table,
993 .num_ports = 1, 649 .num_ports = 1,
994 .open = spcp8x5_open, 650 .open = spcp8x5_open,
995 .close = spcp8x5_close,
996 .dtr_rts = spcp8x5_dtr_rts, 651 .dtr_rts = spcp8x5_dtr_rts,
997 .carrier_raised = spcp8x5_carrier_raised, 652 .carrier_raised = spcp8x5_carrier_raised,
998 .write = spcp8x5_write,
999 .set_termios = spcp8x5_set_termios, 653 .set_termios = spcp8x5_set_termios,
1000 .init_termios = spcp8x5_init_termios, 654 .init_termios = spcp8x5_init_termios,
1001 .ioctl = spcp8x5_ioctl, 655 .ioctl = spcp8x5_ioctl,
1002 .tiocmget = spcp8x5_tiocmget, 656 .tiocmget = spcp8x5_tiocmget,
1003 .tiocmset = spcp8x5_tiocmset, 657 .tiocmset = spcp8x5_tiocmset,
1004 .write_room = spcp8x5_write_room,
1005 .read_bulk_callback = spcp8x5_read_bulk_callback,
1006 .write_bulk_callback = spcp8x5_write_bulk_callback,
1007 .chars_in_buffer = spcp8x5_chars_in_buffer,
1008 .attach = spcp8x5_startup, 658 .attach = spcp8x5_startup,
1009 .release = spcp8x5_release, 659 .release = spcp8x5_release,
660 .process_read_urb = spcp8x5_process_read_urb,
1010}; 661};
1011 662
1012static int __init spcp8x5_init(void) 663static int __init spcp8x5_init(void)