Project

General

Profile

Feature #12756 » init_attempt.patch

Jorge Schrauwen, 2020-09-20 12:20 PM

View differences:

usr/src/uts/common/io/usb/clients/usbser/uchcom/uchcom_dsd.c
150 150
		    uint8_t);
151 151
static int	uchcom_cmd_vendor_update_status(uchcom_state_t *);
152 152
static int	uchcom_cmd_vendor_set_dtr_rts(uchcom_state_t *);
153
static int	uchcom_cmd_vendor_calc_divider_settings(uchcom_state_t *,
153
static int	uchcom_cmd_vendor_calc_divider_settings(uchcom_divider_t *,
154 154
		    uint32_t);
155 155
static int	uchcom_cmd_vendor_set_baudrate(uchcom_state_t *,
156 156
		    uint32_t);
......
196 196
static uint_t	uchcom_errmask = DPRINT_MASK_ALL;
197 197
static uint_t	uchcom_instance_debug = (uint_t)-1;
198 198

  
199
/* divider record */
200
#define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
201
static const struct uchcom_divider_record dividers[] =
202
{
203
	{307200, 307200, UCHCOM_BASE_UNKNOWN, {7, 0xD9, 0}},
204
	{921600, 921600, UCHCOM_BASE_UNKNOWN, {7, 0xF3, 0}},
205
	{2999999, 23530, 6000000, {3, 0, 0}},
206
	{23529, 2942, 750000, {2, 0, 0}},
207
	{2941, 368, 93750, {1, 0, 0}},
208
	{367, 1, 11719, {0, 0, 0}},
209
};
210

  
211
static int uchcom_speedtab[] = {
212
	0,	/* B0 */
213
	50,	/* B50 */
214
	75,	/* B75 */
215
	110,	/* B110 */
216
	134,	/* B134 */
217
	150,	/* B150 */
218
	200,	/* B200 */
219
	300,	/* B300 */
220
	600,	/* B600 */
221
	1200,	/* B1200 */
222
	1800,	/* B1800 */
223
	2400,	/* B2400 */
224
	4800,	/* B4800 */
225
	9600,	/* B9600 */
226
	19200,	/* B19200 */
227
	38400,	/* B38400 */
228
	57600,	/* B57600 */
229
	76800,	/* B76800 */
230
	115200,	/* B115200 */
231
	153600,	/* B153600 */
232
	230400,	/* B230400 */
233
	307200,	/* B307200 */
234
	460800	/* B460800 */
235
};
236

  
199 237
/*
200 238
 * ds_attach
201 239
 */
......
564 602
uchcom_set_port_params(ds_hdl_t hdl, uint_t portno, ds_port_params_t *tp)
565 603
{
566 604
	uchcom_state_t		*uch = (uchcom_state_t *)hdl;
567
	int			rval;
605
	int			rval = USB_SUCCESS;
568 606
	int			i;
607
	uint_t			baud;
569 608
	ds_port_param_entry_t	*pe;
570 609

  
571 610
	if (tp == NULL)
......
573 612

  
574 613
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_set_port_params");
575 614

  
576
	// clear configuration
577
	rval = uchcom_cmd_vendor_ctrl_write(uch, UCHCOM_REQ_RESET, 0, 0);
578
        if (rval != USB_SUCCESS) {
579
                USB_DPRINTF_L2(DPRINT_DEF_PIPE, uch->uch_lh,
580
                    "uchcom_set_port_params: failed to reset!");
581
                return (rval);
582
        }
615
	/*
616
	 *  configure
617
	 *  ----------------------------------------------
618
	 *  the chip doesn't support very much it seems
619
	 *  both freebsd and openbsd seem to default to
620
	 *  8n1 mode and support nothing else.
621
	 *
622
	 *  we do the same here.
623
	 */
624
	for (i = 0, pe = tp->tp_entries; i < tp->tp_cnt; i++, pe++) {
625
		switch (pe->param) {
626
		case DS_PARAM_BAUD:
627
			if (pe->val.ui >= NELEM(uchcom_speedtab)) {
628
				cmn_err(CE_WARN, "XXX: baud range oops");
629
				USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
630
				    "uchcom_set_port_params: unsupported baudrate");
631
				rval = USB_FAILURE;
632
			} else {
633
				baud = uchcom_speedtab[pe->val.ui];
634
			}
635
			break;
636

  
637
		case DS_PARAM_PARITY:
638
			// only supports 8n1
639
			if (pe->val.ui & PARENB) {
640
				cmn_err(CE_WARN, "XXX: parity oops");
641
				USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
642
				    "uchcom_set_port_params: unsupported parity");
643
				rval = USB_FAILURE;
644
			}
645
			break;
646

  
647
		case DS_PARAM_STOPB:
648
			// only supports 8n1
649
			if (pe->val.ui & CSTOPB) {
650
				cmn_err(CE_WARN, "XXX: stopb oops");
651
				USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
652
				    "uchcom_set_port_params: unsupported cstopb");
653
				rval = USB_FAILURE;
654
			}
655
			break;
656

  
657
		case DS_PARAM_CHARSZ:
658
			// only supports 8n1
659
			if (pe->val.ui != CS8) {
660
				cmn_err(CE_WARN, "XXX: charsz oops");
661
				USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
662
					"uchcom_set_port_params: unsupported charsz");
663
				rval = USB_FAILURE;
664
			}
665
			break;
666

  
667
		case DS_PARAM_XON_XOFF:	 /* Software flow control */
668
			break;
669

  
670
		case DS_PARAM_FLOW_CTL:	 /* Hardware flow control */
671
			break;
672

  
673
		default:
674
			USB_DPRINTF_L2(DPRINT_CTLOP, uch->uch_lh,
675
			    "uchcom_set_port_params: bad param %d", pe->param);
676
			rval = USB_FAILURE;
677
			break;
678
		}
679
	}
583 680

  
584
	// configure
585
        for (i = 0, pe = tp->tp_entries; i < tp->tp_cnt; i++, pe++) {
586
                switch (pe->param) {
587
                case DS_PARAM_BAUD:
588
                        switch (pe->val.ui) {
589
                        case B300:
590
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 300");
591
                                break;
592
                        case B600:
593
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 600");
594
                                break;
595
                        case B1200:
596
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 1200");
597
                                break;
598
                        case B2400:
599
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 2400");
600
                                break;
601
                        case B4800:
602
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 4800");
603
                                break;
604
                        case B9600:
605
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 9400");
606
                                break;
607
                        case B19200:
608
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 19200");
609
                                break;
610
                        case B38400:
611
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 38400");
612
                                break;
613
                        case B57600:
614
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 57600");
615
                                break;
616
                        case B115200:
617
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 115200");
618
                                break;
619
                        case B230400:
620
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 230400");
621
                                break;
622
                        case B460800:
623
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 460800");
624
                                break;
625
                        case B921600:
626
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 921600");
627
                                break;
628
                        default:
629
                                USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
630
                                    "uchcom_set_port_params: bad baud %d",
631
                                    pe->val.ui);
632
                                return (USB_FAILURE);
633
                        }
634
                        break;
635

  
636
                case DS_PARAM_PARITY:
637
                        if (pe->val.ui & PARENB) {
638
                                if (pe->val.ui & PARODD)
639
					cmn_err(CE_WARN, "XXX: uchcom_set_port_params par odd");
640
                                else
641
					cmn_err(CE_WARN, "XXX: uchcom_set_port_params par even");
642
                        } else {
643
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params par none");
644
                        }
645
                        break;
646

  
647
                case DS_PARAM_STOPB:
648
                        if (pe->val.ui & CSTOPB)
649
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params stop bits2");
650
                        else {
651
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params stop bits1");
652
                        }
653
                        break;
654

  
655
                case DS_PARAM_CHARSZ:
656
                        switch (pe->val.ui) {
657
                        case CS8:
658
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params csz cs8");
659
                                break;
660
                        default:
661
                                USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
662
                                    "uchcom_set_port_params: bad charsz");
663
                                return (USB_FAILURE);
664
                        }
665
                        break;
666

  
667
                case DS_PARAM_XON_XOFF:         /* Software flow control */
668
                        if ((pe->val.ui & IXON) || (pe->val.ui & IXOFF)) {
669
                                uint8_t xonc = pe->val.uc[0];
670
                                uint8_t xoffc = pe->val.uc[1];
671

  
672
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params soft flow ???");
673
                        }
674
                        break;
675

  
676
                case DS_PARAM_FLOW_CTL:         /* Hardware flow control */
677
                        if (pe->val.ui & (RTSXOFF | CTSXON)) {
678
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params hard flow RTS_CTS_HS");
679
                        }
680
                        if (pe->val.ui & DTRXOFF) {
681
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params hard flow DTR_DSR_HS");
682
                        }
683
                        break;
684
                default:
685
                        USB_DPRINTF_L2(DPRINT_CTLOP, uch->uch_lh,
686
                            "uchcom_set_port_params: bad param %d", pe->param);
687
                        break;
688
                }
689
        }
690 681

  
691
	return (USB_SUCCESS);
682
	if (rval == USB_SUCCESS) {
683
		// reset
684
		rval = uchcom_cmd_vendor_ctrl_write(uch, UCHCOM_REQ_RESET, 0, 0);
685
		if (rval != USB_SUCCESS) {
686
			cmn_err(CE_WARN, "XXX: reset oops");
687
			USB_DPRINTF_L2(DPRINT_DEF_PIPE, uch->uch_lh,
688
			    "uchcom_set_port_params: failed to reset!");
689
			return (rval);
690
		}
691
		rval = uchcom_cmd_vendor_set_baudrate(uch, baud);
692
		if (rval != USB_SUCCESS) {
693
			cmn_err(CE_WARN, "XXX: first baud");
694
			USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
695
			    "uchcom_set_port_params: failed to set baudrate to %d",
696
			    baud);
697
			return (rval);
698
		}
699

  
700
		// configure
701
		if (uch->uch_chip_version < UCHCOM_VER_30) {
702
			rval = uchcom_cmd_vendor_reg_read(uch,	
703
				UCHCOM_REG_LCR1, NULL,
704
				UCHCOM_REG_LCR2, NULL);
705
			rval = uchcom_cmd_vendor_reg_write(uch,
706
				UCHCOM_REG_LCR1, 0x50,
707
				UCHCOM_REG_LCR2, 0x00);
708
		} else {
709
			/*
710
			 * Set up line control:
711
			 * - enable transmit and receive
712
			 * - set 8n1 mode
713
			 * To do: support other sizes, parity, stop bits.
714
			 */
715
			rval = uchcom_cmd_vendor_reg_write(uch,
716
				UCHCOM_REG_LCR1,
717
				UCHCOM_LCR1_RX | UCHCOM_LCR1_TX | UCHCOM_LCR1_CS8,
718
				UCHCOM_REG_LCR2, 0x00);
719
		}
720
		if (rval != USB_SUCCESS) {
721
			cmn_err(CE_WARN, "XXX: init config oops");
722
			USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
723
			    "uchcom_set_port_params: initial configuration failed");
724
			return (rval);
725
		}
726

  
727
		rval = uchcom_cmd_vendor_update_status(uch);
728
		if (rval != USB_SUCCESS) cmn_err(CE_WARN, "XXX: update fail");
729
		rval = uchcom_cmd_vendor_ctrl_write(uch, UCHCOM_REQ_RESET, 0x501f, 0xd90a);
730
		if (rval != USB_SUCCESS) cmn_err(CE_WARN, "XXX: reset fail");
731
		rval = uchcom_cmd_vendor_set_baudrate(uch, uchcom_speedtab[pe->val.ui]);
732
		if (rval != USB_SUCCESS) cmn_err(CE_WARN, "XXX: rate fail");
733
		rval = uchcom_cmd_vendor_set_dtr_rts(uch);
734
		if (rval != USB_SUCCESS) cmn_err(CE_WARN, "XXX: dtr_rts fail");
735
		rval = uchcom_cmd_vendor_update_status(uch);
736
		if (rval != USB_SUCCESS) cmn_err(CE_WARN, "XXX: update fail");
737
	}
738

  
739
	return (rval);
692 740
}
693 741

  
694 742
/*
......
1835 1883
}
1836 1884

  
1837 1885
static int
1838
uchcom_cmd_vendor_calc_divider_settings(uchcom_state_t *uch, uint32_t rate)
1886
uchcom_cmd_vendor_calc_divider_settings(uchcom_divider_t *dp, uint32_t rate)
1839 1887
{
1840
	// XXX: implement me
1841
	return (-1);
1888
	const struct uchcom_divider_record *rp;
1889
	uint32_t div;
1890
	uint32_t rem;
1891
	uint32_t mod;
1892
	uint8_t i;
1893

  
1894
	/* find record */
1895
	for (i = 0; i != nitems(dividers); i++) {
1896
		if (dividers[i].dvr_high >= rate &&
1897
		    dividers[i].dvr_low <= rate) {
1898
			rp = &dividers[i];
1899
			goto found;
1900
		}
1901
	}
1902
	return (USB_FAILURE);
1903

  
1904
found:
1905
	dp->dv_prescaler = rp->dvr_divider.dv_prescaler;
1906
	if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN)
1907
		dp->dv_div = rp->dvr_divider.dv_div;
1908
	else {
1909
		div = rp->dvr_base_clock / rate;
1910
		rem = rp->dvr_base_clock % rate;
1911
		if (div == 0 || div >= 0xFF)
1912
			return (-1);
1913
		if ((rem << 1) >= rate)
1914
			div += 1;
1915
		dp->dv_div = (uint8_t)-div;
1916
	}
1917

  
1918
	mod = (UCHCOM_BPS_MOD_BASE / rate) + UCHCOM_BPS_MOD_BASE_OFS;
1919
	mod = mod + (mod / 2);
1920

  
1921
	dp->dv_mod = (mod + 0xFF) / 0x100;
1922

  
1923
	return (USB_SUCCESS);
1842 1924
}
1843 1925

  
1844 1926
static int
1845 1927
uchcom_cmd_vendor_set_baudrate(uchcom_state_t *uch, uint32_t rate)
1846 1928
{
1847
	// XXX: implement me
1848
	return (USB_FAILURE);
1929
	int rval;
1930
	struct uchcom_divider dv;
1931

  
1932
	if (uchcom_cmd_vendor_calc_divider_settings(&dv, rate))
1933
		return (USB_FAILURE);
1934

  
1935
	/*
1936
	 * According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE,
1937
	 * otherwise the chip will buffer data.
1938
	 */
1939
	rval = uchcom_cmd_vendor_reg_write(uch,
1940
		UCHCOM_REG_BPS_PRE, dv.dv_prescaler | 0x80,
1941
		UCHCOM_REG_BPS_DIV, dv.dv_div);
1942
	if (rval == USB_SUCCESS)
1943
		rval = uchcom_cmd_vendor_reg_write(uch,
1944
			UCHCOM_REG_BPS_MOD, dv.dv_mod,
1945
			UCHCOM_REG_BPS_PAD, 0);
1946

  
1947
	return (rval);
1849 1948
}
1850 1949

  
1851 1950
/*
usr/src/uts/common/sys/usb/clients/usbser/uchcom/uchcom_reg.h
48 48

  
49 49
#define	UCHCOM_REG_STAT1	0x06
50 50
#define	UCHCOM_REG_STAT2	0x07
51
#define	UCHCOM_REG_BPS_PRE	0x12
52
#define	UCHCOM_REG_BPS_DIV	0x13
53
#define	UCHCOM_REG_BPS_MOD	0x14
54
#define	UCHCOM_REG_BPS_PAD	0x0F
55
#define	UCHCOM_REG_BREAK1	0x05
56
#define	UCHCOM_REG_LCR1		0x18
57
#define	UCHCOM_REG_LCR2		0x25
51 58

  
59
#define	UCHCOM_BASE_UNKNOWN	0
60
#define	UCHCOM_BPS_MOD_BASE	20000000
61
#define	UCHCOM_BPS_MOD_BASE_OFS	1100
52 62

  
53 63
#define	UCHCOM_DTR_MASK		0x20
54 64
#define	UCHCOM_RTS_MASK		0x40
55 65

  
66
#define	UCHCOM_LCR1_MASK	0xAF
67
#define	UCHCOM_LCR2_MASK	0x07
68
#define	UCHCOM_LCR1_RX		0x80
69
#define	UCHCOM_LCR1_TX		0x40
70
#define	UCHCOM_LCR1_PARENB	0x08
71
#define	UCHCOM_LCR1_CS8		0x03
72
#define	UCHCOM_LCR2_PAREVEN	0x07
73
#define	UCHCOM_LCR2_PARODD	0x06
74
#define	UCHCOM_LCR2_PARMARK	0x05
75
#define	UCHCOM_LCR2_PARSPACE	0x04
76

  
56 77
/*
57 78
 * XXX - these magic numbers come from Linux (drivers/usb/serial/ch341.c).
58 79
 * The manufacturer was unresponsive when asked for documentation.
usr/src/uts/common/sys/usb/clients/usbser/uchcom/uchcom_var.h
112 112
	uch_bulkout_ph
113 113
}))
114 114

  
115
typedef struct uchcom_divider
116
{
117
	uint8_t		dv_prescaler;
118
	uint8_t		dv_div;
119
	uint8_t		dv_mod;
120
} uchcom_divider_t;
121

  
122
typedef struct uchcom_divider_record
123
{
124
	uint32_t		dvr_high;
125
	uint32_t		dvr_low;
126
	uint32_t		dvr_base_clock;
127
	struct uchcom_divider	dvr_divider;
128
} uchcom_devider_record_t;
129

  
115 130
/* port state */
116 131
enum {
117 132
	UCHCOM_PORT_CLOSED,			/* port is closed */
......
155 170
#define	DPRINT_PM		0x00004000
156 171
#define	DPRINT_MASK_ALL		0xFFFFFFFF
157 172

  
173
/*
174
 * misc macros
175
 */
176
#define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
177

  
158 178
#ifdef	__cplusplus
159 179
}
160 180
#endif
(2-2/2)