cp210x.c (d1620ca9e7bb0030068c3b45b653defde8839dac) cp210x.c (0b238583ac8db66762bba021de1b7c60b6bc29ad)
1/*
2 * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
3 *
4 * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.

--- 25 unchanged lines hidden (view full) ---

34 * Function Prototypes
35 */
36static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
37static void cp210x_close(struct usb_serial_port *);
38static void cp210x_get_termios(struct tty_struct *,
39 struct usb_serial_port *port);
40static void cp210x_get_termios_port(struct usb_serial_port *port,
41 unsigned int *cflagp, unsigned int *baudp);
1/*
2 * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
3 *
4 * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.

--- 25 unchanged lines hidden (view full) ---

34 * Function Prototypes
35 */
36static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
37static void cp210x_close(struct usb_serial_port *);
38static void cp210x_get_termios(struct tty_struct *,
39 struct usb_serial_port *port);
40static void cp210x_get_termios_port(struct usb_serial_port *port,
41 unsigned int *cflagp, unsigned int *baudp);
42static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
43 struct ktermios *);
44static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
45 struct ktermios*);
46static int cp210x_tiocmget(struct tty_struct *);
47static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
48static int cp210x_tiocmset_port(struct usb_serial_port *port,
49 unsigned int, unsigned int);
50static void cp210x_break_ctl(struct tty_struct *, int);
51static int cp210x_startup(struct usb_serial *);

--- 83 unchanged lines hidden (view full) ---

135 { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
136 { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
137 { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
138 { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
139 { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
140 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
141 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
142 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
42static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
43 struct ktermios*);
44static int cp210x_tiocmget(struct tty_struct *);
45static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
46static int cp210x_tiocmset_port(struct usb_serial_port *port,
47 unsigned int, unsigned int);
48static void cp210x_break_ctl(struct tty_struct *, int);
49static int cp210x_startup(struct usb_serial *);

--- 83 unchanged lines hidden (view full) ---

133 { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
134 { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
135 { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
136 { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
137 { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
138 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
139 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
140 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
143 { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
144 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
145 { } /* Terminating Entry */
146};
147
148MODULE_DEVICE_TABLE(usb, id_table);
149
150static struct usb_driver cp210x_driver = {
151 .name = "cp210x",

--- 47 unchanged lines hidden (view full) ---

199#define CP210X_GET_COMM_STATUS 0x10
200#define CP210X_RESET 0x11
201#define CP210X_PURGE 0x12
202#define CP210X_SET_FLOW 0x13
203#define CP210X_GET_FLOW 0x14
204#define CP210X_EMBED_EVENTS 0x15
205#define CP210X_GET_EVENTSTATE 0x16
206#define CP210X_SET_CHARS 0x19
141 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
142 { } /* Terminating Entry */
143};
144
145MODULE_DEVICE_TABLE(usb, id_table);
146
147static struct usb_driver cp210x_driver = {
148 .name = "cp210x",

--- 47 unchanged lines hidden (view full) ---

196#define CP210X_GET_COMM_STATUS 0x10
197#define CP210X_RESET 0x11
198#define CP210X_PURGE 0x12
199#define CP210X_SET_FLOW 0x13
200#define CP210X_GET_FLOW 0x14
201#define CP210X_EMBED_EVENTS 0x15
202#define CP210X_GET_EVENTSTATE 0x16
203#define CP210X_SET_CHARS 0x19
207#define CP210X_GET_BAUDRATE 0x1D
208#define CP210X_SET_BAUDRATE 0x1E
209
210/* CP210X_IFC_ENABLE */
211#define UART_ENABLE 0x0001
212#define UART_DISABLE 0x0000
213
214/* CP210X_(SET|GET)_BAUDDIV */
215#define BAUD_RATE_GEN_FREQ 0x384000
216

--- 62 unchanged lines hidden (view full) ---

279 /* Convert data into an array of integers */
280 for (i = 0; i < length; i++)
281 data[i] = le32_to_cpu(buf[i]);
282
283 kfree(buf);
284
285 if (result != size) {
286 dbg("%s - Unable to send config request, "
204
205/* CP210X_IFC_ENABLE */
206#define UART_ENABLE 0x0001
207#define UART_DISABLE 0x0000
208
209/* CP210X_(SET|GET)_BAUDDIV */
210#define BAUD_RATE_GEN_FREQ 0x384000
211

--- 62 unchanged lines hidden (view full) ---

274 /* Convert data into an array of integers */
275 for (i = 0; i < length; i++)
276 data[i] = le32_to_cpu(buf[i]);
277
278 kfree(buf);
279
280 if (result != size) {
281 dbg("%s - Unable to send config request, "
287 "request=0x%x size=%d result=%d\n",
282 "request=0x%x size=%d result=%d",
288 __func__, request, size, result);
289 if (result > 0)
290 result = -EPROTO;
291
292 return result;
293 }
294
295 return 0;

--- 37 unchanged lines hidden (view full) ---

333 request, REQTYPE_HOST_TO_DEVICE, data[0],
334 0, NULL, 0, 300);
335 }
336
337 kfree(buf);
338
339 if ((size > 2 && result != size) || result < 0) {
340 dbg("%s - Unable to send request, "
283 __func__, request, size, result);
284 if (result > 0)
285 result = -EPROTO;
286
287 return result;
288 }
289
290 return 0;

--- 37 unchanged lines hidden (view full) ---

328 request, REQTYPE_HOST_TO_DEVICE, data[0],
329 0, NULL, 0, 300);
330 }
331
332 kfree(buf);
333
334 if ((size > 2 && result != size) || result < 0) {
335 dbg("%s - Unable to send request, "
341 "request=0x%x size=%d result=%d\n",
336 "request=0x%x size=%d result=%d",
342 __func__, request, size, result);
343 if (result > 0)
344 result = -EPROTO;
345
346 return result;
347 }
348
349 return 0;

--- 10 unchanged lines hidden (view full) ---

360 return cp210x_set_config(port, request, &data, 2);
361}
362
363/*
364 * cp210x_quantise_baudrate
365 * Quantises the baud rate as per AN205 Table 1
366 */
367static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
337 __func__, request, size, result);
338 if (result > 0)
339 result = -EPROTO;
340
341 return result;
342 }
343
344 return 0;

--- 10 unchanged lines hidden (view full) ---

355 return cp210x_set_config(port, request, &data, 2);
356}
357
358/*
359 * cp210x_quantise_baudrate
360 * Quantises the baud rate as per AN205 Table 1
361 */
362static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
368 if (baud <= 300)
369 baud = 300;
363 if (baud <= 56) baud = 0;
364 else if (baud <= 300) baud = 300;
370 else if (baud <= 600) baud = 600;
371 else if (baud <= 1200) baud = 1200;
372 else if (baud <= 1800) baud = 1800;
373 else if (baud <= 2400) baud = 2400;
374 else if (baud <= 4000) baud = 4000;
375 else if (baud <= 4803) baud = 4800;
376 else if (baud <= 7207) baud = 7200;
377 else if (baud <= 9612) baud = 9600;

--- 11 unchanged lines hidden (view full) ---

389 else if (baud <= 129347) baud = 128000;
390 else if (baud <= 156868) baud = 153600;
391 else if (baud <= 237832) baud = 230400;
392 else if (baud <= 254234) baud = 250000;
393 else if (baud <= 273066) baud = 256000;
394 else if (baud <= 491520) baud = 460800;
395 else if (baud <= 567138) baud = 500000;
396 else if (baud <= 670254) baud = 576000;
365 else if (baud <= 600) baud = 600;
366 else if (baud <= 1200) baud = 1200;
367 else if (baud <= 1800) baud = 1800;
368 else if (baud <= 2400) baud = 2400;
369 else if (baud <= 4000) baud = 4000;
370 else if (baud <= 4803) baud = 4800;
371 else if (baud <= 7207) baud = 7200;
372 else if (baud <= 9612) baud = 9600;

--- 11 unchanged lines hidden (view full) ---

384 else if (baud <= 129347) baud = 128000;
385 else if (baud <= 156868) baud = 153600;
386 else if (baud <= 237832) baud = 230400;
387 else if (baud <= 254234) baud = 250000;
388 else if (baud <= 273066) baud = 256000;
389 else if (baud <= 491520) baud = 460800;
390 else if (baud <= 567138) baud = 500000;
391 else if (baud <= 670254) baud = 576000;
397 else if (baud < 1000000)
398 baud = 921600;
399 else if (baud > 2000000)
400 baud = 2000000;
392 else if (baud <= 1053257) baud = 921600;
393 else if (baud <= 1474560) baud = 1228800;
394 else if (baud <= 2457600) baud = 1843200;
395 else baud = 3686400;
401 return baud;
402}
403
404static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
405{
406 int result;
407
408 dbg("%s - port %d", __func__, port->number);
409
410 result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
411 UART_ENABLE);
412 if (result) {
413 dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
414 return result;
415 }
416
396 return baud;
397}
398
399static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
400{
401 int result;
402
403 dbg("%s - port %d", __func__, port->number);
404
405 result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
406 UART_ENABLE);
407 if (result) {
408 dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
409 return result;
410 }
411
412 result = usb_serial_generic_open(tty, port);
413 if (result)
414 return result;
415
417 /* Configure the termios structure */
418 cp210x_get_termios(tty, port);
416 /* Configure the termios structure */
417 cp210x_get_termios(tty, port);
419
420 /* The baud rate must be initialised on cp2104 */
421 if (tty)
422 cp210x_change_speed(tty, port, NULL);
423
424 return usb_serial_generic_open(tty, port);
418 return 0;
425}
426
427static void cp210x_close(struct usb_serial_port *port)
428{
429 dbg("%s - port %d", __func__, port->number);
430
431 usb_serial_generic_close(port);
432

--- 35 unchanged lines hidden (view full) ---

468 unsigned int *cflagp, unsigned int *baudp)
469{
470 unsigned int cflag, modem_ctl[4];
471 unsigned int baud;
472 unsigned int bits;
473
474 dbg("%s - port %d", __func__, port->number);
475
419}
420
421static void cp210x_close(struct usb_serial_port *port)
422{
423 dbg("%s - port %d", __func__, port->number);
424
425 usb_serial_generic_close(port);
426

--- 35 unchanged lines hidden (view full) ---

462 unsigned int *cflagp, unsigned int *baudp)
463{
464 unsigned int cflag, modem_ctl[4];
465 unsigned int baud;
466 unsigned int bits;
467
468 dbg("%s - port %d", __func__, port->number);
469
476 cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
470 cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
471 /* Convert to baudrate */
472 if (baud)
473 baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
477
478 dbg("%s - baud rate = %d", __func__, baud);
479 *baudp = baud;
480
481 cflag = *cflagp;
482
483 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
484 cflag &= ~CSIZE;

--- 92 unchanged lines hidden (view full) ---

577 } else {
578 dbg("%s - flow control = NONE", __func__);
579 cflag &= ~CRTSCTS;
580 }
581
582 *cflagp = cflag;
583}
584
474
475 dbg("%s - baud rate = %d", __func__, baud);
476 *baudp = baud;
477
478 cflag = *cflagp;
479
480 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
481 cflag &= ~CSIZE;

--- 92 unchanged lines hidden (view full) ---

574 } else {
575 dbg("%s - flow control = NONE", __func__);
576 cflag &= ~CRTSCTS;
577 }
578
579 *cflagp = cflag;
580}
581
585/*
586 * CP2101 supports the following baud rates:
587 *
588 * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
589 * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
590 *
591 * CP2102 and CP2103 support the following additional rates:
592 *
593 * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
594 * 576000
595 *
596 * The device will map a requested rate to a supported one, but the result
597 * of requests for rates greater than 1053257 is undefined (see AN205).
598 *
599 * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
600 * respectively, with an error less than 1%. The actual rates are determined
601 * by
602 *
603 * div = round(freq / (2 x prescale x request))
604 * actual = freq / (2 x prescale x div)
605 *
606 * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
607 * or 1 otherwise.
608 * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
609 * otherwise.
610 */
611static void cp210x_change_speed(struct tty_struct *tty,
612 struct usb_serial_port *port, struct ktermios *old_termios)
613{
614 u32 baud;
615
616 baud = tty->termios->c_ospeed;
617
618 /* This maps the requested rate to a rate valid on cp2102 or cp2103,
619 * or to an arbitrary rate in [1M,2M].
620 *
621 * NOTE: B0 is not implemented.
622 */
623 baud = cp210x_quantise_baudrate(baud);
624
625 dbg("%s - setting baud rate to %u", __func__, baud);
626 if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
627 sizeof(baud))) {
628 dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
629 if (old_termios)
630 baud = old_termios->c_ospeed;
631 else
632 baud = 9600;
633 }
634
635 tty_encode_baud_rate(tty, baud, baud);
636}
637
638static void cp210x_set_termios(struct tty_struct *tty,
639 struct usb_serial_port *port, struct ktermios *old_termios)
640{
641 unsigned int cflag, old_cflag;
582static void cp210x_set_termios(struct tty_struct *tty,
583 struct usb_serial_port *port, struct ktermios *old_termios)
584{
585 unsigned int cflag, old_cflag;
642 unsigned int bits;
586 unsigned int baud = 0, bits;
643 unsigned int modem_ctl[4];
644
645 dbg("%s - port %d", __func__, port->number);
646
647 if (!tty)
648 return;
649
650 cflag = tty->termios->c_cflag;
651 old_cflag = old_termios->c_cflag;
587 unsigned int modem_ctl[4];
588
589 dbg("%s - port %d", __func__, port->number);
590
591 if (!tty)
592 return;
593
594 cflag = tty->termios->c_cflag;
595 old_cflag = old_termios->c_cflag;
596 baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
652
597
653 if (tty->termios->c_ospeed != old_termios->c_ospeed)
654 cp210x_change_speed(tty, port, old_termios);
598 /* If the baud rate is to be updated*/
599 if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
600 dbg("%s - Setting baud rate to %d baud", __func__,
601 baud);
602 if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
603 ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
604 dbg("Baud rate requested not supported by device");
605 baud = tty_termios_baud_rate(old_termios);
606 }
607 }
608 /* Report back the resulting baud rate */
609 tty_encode_baud_rate(tty, baud, baud);
655
656 /* If the number of data bits is to be updated */
657 if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
658 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
659 bits &= ~BITS_DATA_MASK;
660 switch (cflag & CSIZE) {
661 case CS5:
662 bits |= BITS_DATA_5;

--- 13 unchanged lines hidden (view full) ---

676 break;
677 /*case CS9:
678 bits |= BITS_DATA_9;
679 dbg("%s - data bits = 9", __func__);
680 break;*/
681 default:
682 dbg("cp210x driver does not "
683 "support the number of bits requested,"
610
611 /* If the number of data bits is to be updated */
612 if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
613 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
614 bits &= ~BITS_DATA_MASK;
615 switch (cflag & CSIZE) {
616 case CS5:
617 bits |= BITS_DATA_5;

--- 13 unchanged lines hidden (view full) ---

631 break;
632 /*case CS9:
633 bits |= BITS_DATA_9;
634 dbg("%s - data bits = 9", __func__);
635 break;*/
636 default:
637 dbg("cp210x driver does not "
638 "support the number of bits requested,"
684 " using 8 bit mode\n");
639 " using 8 bit mode");
685 bits |= BITS_DATA_8;
686 break;
687 }
688 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
689 dbg("Number of data bits requested "
640 bits |= BITS_DATA_8;
641 break;
642 }
643 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
644 dbg("Number of data bits requested "
690 "not supported by device\n");
645 "not supported by device");
691 }
692
693 if ((cflag & (PARENB|PARODD|CMSPAR)) !=
694 (old_cflag & (PARENB|PARODD|CMSPAR))) {
695 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
696 bits &= ~BITS_PARITY_MASK;
697 if (cflag & PARENB) {
698 if (cflag & CMSPAR) {

--- 10 unchanged lines hidden (view full) ---

709 dbg("%s - parity = ODD", __func__);
710 } else {
711 bits |= BITS_PARITY_EVEN;
712 dbg("%s - parity = EVEN", __func__);
713 }
714 }
715 }
716 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
646 }
647
648 if ((cflag & (PARENB|PARODD|CMSPAR)) !=
649 (old_cflag & (PARENB|PARODD|CMSPAR))) {
650 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
651 bits &= ~BITS_PARITY_MASK;
652 if (cflag & PARENB) {
653 if (cflag & CMSPAR) {

--- 10 unchanged lines hidden (view full) ---

664 dbg("%s - parity = ODD", __func__);
665 } else {
666 bits |= BITS_PARITY_EVEN;
667 dbg("%s - parity = EVEN", __func__);
668 }
669 }
670 }
671 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
717 dbg("Parity mode not supported "
718 "by device\n");
672 dbg("Parity mode not supported by device");
719 }
720
721 if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
722 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
723 bits &= ~BITS_STOP_MASK;
724 if (cflag & CSTOPB) {
725 bits |= BITS_STOP_2;
726 dbg("%s - stop bits = 2", __func__);
727 } else {
728 bits |= BITS_STOP_1;
729 dbg("%s - stop bits = 1", __func__);
730 }
731 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
732 dbg("Number of stop bits requested "
673 }
674
675 if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
676 cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
677 bits &= ~BITS_STOP_MASK;
678 if (cflag & CSTOPB) {
679 bits |= BITS_STOP_2;
680 dbg("%s - stop bits = 2", __func__);
681 } else {
682 bits |= BITS_STOP_1;
683 dbg("%s - stop bits = 1", __func__);
684 }
685 if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
686 dbg("Number of stop bits requested "
733 "not supported by device\n");
687 "not supported by device");
734 }
735
736 if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
737 cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
738 dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
739 __func__, modem_ctl[0], modem_ctl[1],
740 modem_ctl[2], modem_ctl[3]);
741

--- 144 unchanged lines hidden ---
688 }
689
690 if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
691 cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
692 dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
693 __func__, modem_ctl[0], modem_ctl[1],
694 modem_ctl[2], modem_ctl[3]);
695

--- 144 unchanged lines hidden ---