aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_gsm.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-11-04 11:17:03 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-11 14:35:58 -0500
commitc2f2f0000bb69f067fea12624272e6a58a811702 (patch)
tree05cfb995864a877c12a1a5bfe4fc2c3eefe99620 /drivers/tty/n_gsm.c
parent304e12665a4a7b8b25dfe8c64fa4fd56a04a67ea (diff)
n_gsm: Fix support for legacy encoding
The mux supports several encoding schemes. Encoding 0 is a "not recommended" mode still sometimes used. This has now been tested with hardware that supports this mode, and found wanting. Fix the FCS handling in this mode and correct the state machine. Signed-off-by: Ken Mills <ken.k.mills@intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/tty/n_gsm.c')
-rw-r--r--drivers/tty/n_gsm.c59
1 files changed, 46 insertions, 13 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 04ef3ef0a422..5256087dd81b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -184,6 +184,9 @@ struct gsm_mux {
184#define GSM_DATA 5 184#define GSM_DATA 5
185#define GSM_FCS 6 185#define GSM_FCS 6
186#define GSM_OVERRUN 7 186#define GSM_OVERRUN 7
187#define GSM_LEN0 8
188#define GSM_LEN1 9
189#define GSM_SSOF 10
187 unsigned int len; 190 unsigned int len;
188 unsigned int address; 191 unsigned int address;
189 unsigned int count; 192 unsigned int count;
@@ -191,6 +194,7 @@ struct gsm_mux {
191 int encoding; 194 int encoding;
192 u8 control; 195 u8 control;
193 u8 fcs; 196 u8 fcs;
197 u8 received_fcs;
194 u8 *txframe; /* TX framing buffer */ 198 u8 *txframe; /* TX framing buffer */
195 199
196 /* Methods for the receiver side */ 200 /* Methods for the receiver side */
@@ -1623,7 +1627,6 @@ static void gsm_dlci_free(struct gsm_dlci *dlci)
1623 kfree(dlci); 1627 kfree(dlci);
1624} 1628}
1625 1629
1626
1627/* 1630/*
1628 * LAPBish link layer logic 1631 * LAPBish link layer logic
1629 */ 1632 */
@@ -1648,6 +1651,8 @@ static void gsm_queue(struct gsm_mux *gsm)
1648 1651
1649 if ((gsm->control & ~PF) == UI) 1652 if ((gsm->control & ~PF) == UI)
1650 gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); 1653 gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
1654 /* generate final CRC with received FCS */
1655 gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
1651 if (gsm->fcs != GOOD_FCS) { 1656 if (gsm->fcs != GOOD_FCS) {
1652 gsm->bad_fcs++; 1657 gsm->bad_fcs++;
1653 if (debug & 4) 1658 if (debug & 4)
@@ -1746,6 +1751,8 @@ invalid:
1746 1751
1747static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) 1752static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
1748{ 1753{
1754 unsigned int len;
1755
1749 switch (gsm->state) { 1756 switch (gsm->state) {
1750 case GSM_SEARCH: /* SOF marker */ 1757 case GSM_SEARCH: /* SOF marker */
1751 if (c == GSM0_SOF) { 1758 if (c == GSM0_SOF) {
@@ -1754,8 +1761,8 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
1754 gsm->len = 0; 1761 gsm->len = 0;
1755 gsm->fcs = INIT_FCS; 1762 gsm->fcs = INIT_FCS;
1756 } 1763 }
1757 break; /* Address EA */ 1764 break;
1758 case GSM_ADDRESS: 1765 case GSM_ADDRESS: /* Address EA */
1759 gsm->fcs = gsm_fcs_add(gsm->fcs, c); 1766 gsm->fcs = gsm_fcs_add(gsm->fcs, c);
1760 if (gsm_read_ea(&gsm->address, c)) 1767 if (gsm_read_ea(&gsm->address, c))
1761 gsm->state = GSM_CONTROL; 1768 gsm->state = GSM_CONTROL;
@@ -1763,9 +1770,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
1763 case GSM_CONTROL: /* Control Byte */ 1770 case GSM_CONTROL: /* Control Byte */
1764 gsm->fcs = gsm_fcs_add(gsm->fcs, c); 1771 gsm->fcs = gsm_fcs_add(gsm->fcs, c);
1765 gsm->control = c; 1772 gsm->control = c;
1766 gsm->state = GSM_LEN; 1773 gsm->state = GSM_LEN0;
1767 break; 1774 break;
1768 case GSM_LEN: /* Length EA */ 1775 case GSM_LEN0: /* Length EA */
1769 gsm->fcs = gsm_fcs_add(gsm->fcs, c); 1776 gsm->fcs = gsm_fcs_add(gsm->fcs, c);
1770 if (gsm_read_ea(&gsm->len, c)) { 1777 if (gsm_read_ea(&gsm->len, c)) {
1771 if (gsm->len > gsm->mru) { 1778 if (gsm->len > gsm->mru) {
@@ -1774,8 +1781,28 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
1774 break; 1781 break;
1775 } 1782 }
1776 gsm->count = 0; 1783 gsm->count = 0;
1777 gsm->state = GSM_DATA; 1784 if (!gsm->len)
1785 gsm->state = GSM_FCS;
1786 else
1787 gsm->state = GSM_DATA;
1788 break;
1778 } 1789 }
1790 gsm->state = GSM_LEN1;
1791 break;
1792 case GSM_LEN1:
1793 gsm->fcs = gsm_fcs_add(gsm->fcs, c);
1794 len = c;
1795 gsm->len |= len << 7;
1796 if (gsm->len > gsm->mru) {
1797 gsm->bad_size++;
1798 gsm->state = GSM_SEARCH;
1799 break;
1800 }
1801 gsm->count = 0;
1802 if (!gsm->len)
1803 gsm->state = GSM_FCS;
1804 else
1805 gsm->state = GSM_DATA;
1779 break; 1806 break;
1780 case GSM_DATA: /* Data */ 1807 case GSM_DATA: /* Data */
1781 gsm->buf[gsm->count++] = c; 1808 gsm->buf[gsm->count++] = c;
@@ -1783,16 +1810,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
1783 gsm->state = GSM_FCS; 1810 gsm->state = GSM_FCS;
1784 break; 1811 break;
1785 case GSM_FCS: /* FCS follows the packet */ 1812 case GSM_FCS: /* FCS follows the packet */
1786 gsm->fcs = c; 1813 gsm->received_fcs = c;
1814 if (c == GSM0_SOF) {
1815 gsm->state = GSM_SEARCH;
1816 break;
1817 }
1787 gsm_queue(gsm); 1818 gsm_queue(gsm);
1788 /* And then back for the next frame */ 1819 gsm->state = GSM_SSOF;
1789 gsm->state = GSM_SEARCH; 1820 break;
1821 case GSM_SSOF:
1822 if (c == GSM0_SOF) {
1823 gsm->state = GSM_SEARCH;
1824 break;
1825 }
1790 break; 1826 break;
1791 } 1827 }
1792} 1828}
1793 1829
1794/** 1830/**
1795 * gsm0_receive - perform processing for non-transparency 1831 * gsm1_receive - perform processing for non-transparency
1796 * @gsm: gsm data for this ldisc instance 1832 * @gsm: gsm data for this ldisc instance
1797 * @c: character 1833 * @c: character
1798 * 1834 *
@@ -2032,9 +2068,6 @@ struct gsm_mux *gsm_alloc_mux(void)
2032} 2068}
2033EXPORT_SYMBOL_GPL(gsm_alloc_mux); 2069EXPORT_SYMBOL_GPL(gsm_alloc_mux);
2034 2070
2035
2036
2037
2038/** 2071/**
2039 * gsmld_output - write to link 2072 * gsmld_output - write to link
2040 * @gsm: our mux 2073 * @gsm: our mux