1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  * This driver includes code for Keyspan USA49WLC/USA19HS adapters. It is a
32  * device-specific driver (DSD) working with USB generic serial driver (GSD). It
33  * implements the USB-to-serial device-specific driver interface (DSDI) which is
34  * offered by GSD. The interface is defined by ds_ops_t structure.
35  *
36  * For USA49WLC, it's necessary to download firmware every time the device is
37  * plugged. Before the firmware is downloaded, we say that the device is in
38  * "firmware mode", and the attach routin is keyspan_pre_attach(). After
39  * downloading, the device's product id will change to 0x12a. Then the device
40  * will be enumerated again and another attach for the new product id will
41  * begin. No firmware is included in the driver. The functions of USA49WLC is
42  * disabled.
43  *
44  * For USA19HS, no need to download firmware since it can be kept in the
45  * device's memory.
46  *
47  * For both models, it's necessary to check and switch their configrations at
48  * the beginning of attach, since each of them has two configrations. This
49  * driver uses the one whose endpoints are all bulk.
50  *
51  * Some of Keyspan adapters have only one port, some have two or four ports.
52  * This driver supports up to four ports. Each port has its own states (traced
53  * by keyspan_port structure) and can be operated independently.
54  *
55  * port_state:
56  *
57  *   KEYSPAN_PORT_NOT_INIT
58  *	    |
59  *	    |
60  *     attach_ports
61  *	    |
62  *	    |
63  *	    |
64  *	    v
65  *   KEYSPAN_PORT_CLOSED <-----close-------<---- +
66  *	|					 |
67  *	|					 |
68  *	|					 |
69  *  open_port					 |
70  *	|					 |
71  *	|					 |
72  *	v					 |
73  * KEYSPAN_PORT_OPENING ---open_hw_port---> USBSER_PORT_OPEN
74  *
75  * Each port has its own data in/out pipes and each pipe also has its own states
76  * (traced by keyspan_pipe structure). The pipe states is as following:
77  *
78  * pipe_state:
79  *
80  *	  KEYSPAN_PIPE_NOT_INIT
81  *		|	^
82  *		|	|
83  * keyspan_init_pipes  keyspan_fini_pipes
84  *		|	|
85  *		v	|
86  *	   KEYSPAN_PIPE_CLOSED ------------->-----------+
87  *		  ^					|
88  *		  |			  reconnect/resume/open_port
89  *		  |					|
90  *    disconnect/suspend/close_port			|
91  *		  |					v
92  *		  +---------<------------------ KEYSPAN_PIPE_OPEN
93  *
94  * To control the device and get its status in a timely way, this driver makes
95  * use of two global bulk endpoints for cmd and status on the device. The pipes
96  * for cmd/status will be opened during attach. For multi-port devices, one of
97  * the cmd/status message fields will designate which port this message is for.
98  *
99  * This driver can be easily extended to support more Keyspan adapter models.
100  * You need the following steps to reach the aim:
101  * 1. Add the model specific data structures, like cmd/status message structure.
102  * 2. If the device need firmware downloaded, add the firmware code as a header
103  * file, and add code to keyspan_pre_attach() as what were done for USA49WLC.
104  * 3. Add several model specific functions, like keyspan_build_cmd_msg_*,
105  * keyspan_default_port_params_*, keyspan_save_port_params_*, etc. The functions
106  * for USA19HS and USA49WLC can be taken as examples.
107  * 4. Add model specific code to the "switch (id_product) {...}" sentences.
108  */
109 
110 /*
111  *
112  * keyspan driver glue code
113  *
114  */
115 #include <sys/types.h>
116 #include <sys/param.h>
117 #include <sys/stream.h>
118 #include <sys/conf.h>
119 #include <sys/ddi.h>
120 #include <sys/sunddi.h>
121 
122 #define	USBDRV_MAJOR_VER	2
123 #define	USBDRV_MINOR_VER	0
124 
125 #include <sys/usb/usba.h>
126 
127 #include <sys/usb/clients/usbser/usbser.h>
128 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
129 
130 #include <sys/byteorder.h>
131 #include <sys/strsun.h>
132 
133 /* configuration entry points */
134 static int	usbser_keyspan_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
135 		void **);
136 static int	usbser_keyspan_attach(dev_info_t *, ddi_attach_cmd_t);
137 static int	usbser_keyspan_detach(dev_info_t *, ddi_detach_cmd_t);
138 static int	usbser_keyspan_open(queue_t *, dev_t *, int, int, cred_t *);
139 
140 /* functions related with set config or firmware download */
141 static int	keyspan_pre_attach(dev_info_t *, ddi_attach_cmd_t, void *);
142 static int	keyspan_set_cfg(dev_info_t *);
143 static int	keyspan_pre_detach(dev_info_t *, ddi_detach_cmd_t, void *);
144 static boolean_t keyspan_need_fw(usb_client_dev_data_t *);
145 static int	keyspan_set_reg(keyspan_pipe_t *, uchar_t);
146 static int	keyspan_write_memory(keyspan_pipe_t *, uint16_t, uchar_t *,
147 		uint16_t, uint8_t);
148 static int	keyspan_download_firmware(keyspan_pre_state_t *);
149 
150 static void    *usbser_keyspan_statep;	/* soft state */
151 
152 extern ds_ops_t ds_ops;		/* DSD operations */
153 
154 /*
155  * STREAMS structures
156  */
157 struct module_info usbser_keyspan_modinfo = {
158 	0,			/* module id */
159 	"usbsksp",		/* module name */
160 	USBSER_MIN_PKTSZ,	/* min pkt size */
161 	USBSER_MAX_PKTSZ,	/* max pkt size */
162 	USBSER_HIWAT,		/* hi watermark */
163 	USBSER_LOWAT		/* low watermark */
164 };
165 
166 static struct qinit usbser_keyspan_rinit = {
167 	putq,
168 	usbser_rsrv,
169 	usbser_keyspan_open,
170 	usbser_close,
171 	NULL,
172 	&usbser_keyspan_modinfo,
173 	NULL
174 };
175 
176 static struct qinit usbser_keyspan_winit = {
177 	usbser_wput,
178 	usbser_wsrv,
179 	NULL,
180 	NULL,
181 	NULL,
182 	&usbser_keyspan_modinfo,
183 	NULL
184 };
185 
186 struct streamtab usbser_keyspan_str_info = {
187 	&usbser_keyspan_rinit, &usbser_keyspan_winit, NULL, NULL
188 };
189 
190 static struct cb_ops usbser_keyspan_cb_ops = {
191 	nodev,			/* cb_open */
192 	nodev,			/* cb_close */
193 	nodev,			/* cb_strategy */
194 	nodev,			/* cb_print */
195 	nodev,			/* cb_dump */
196 	nodev,			/* cb_read */
197 	nodev,			/* cb_write */
198 	nodev,			/* cb_ioctl */
199 	nodev,			/* cb_devmap */
200 	nodev,			/* cb_mmap */
201 	nodev,			/* cb_segmap */
202 	nochpoll,		/* cb_chpoll */
203 	ddi_prop_op,		/* cb_prop_op */
204 	&usbser_keyspan_str_info,	/* cb_stream */
205 	(int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG)	/* cb_flag */
206 };
207 
208 /*
209  * auto configuration ops
210  */
211 struct dev_ops usbser_keyspan_ops = {
212 	DEVO_REV,		/* devo_rev */
213 	0,			/* devo_refcnt */
214 	usbser_keyspan_getinfo,	/* devo_getinfo */
215 	nulldev,		/* devo_identify */
216 	nulldev,		/* devo_probe */
217 	usbser_keyspan_attach,	/* devo_attach */
218 	usbser_keyspan_detach,	/* devo_detach */
219 	nodev,			/* devo_reset */
220 	&usbser_keyspan_cb_ops,	/* devo_cb_ops */
221 	(struct bus_ops *)NULL,	/* devo_bus_ops */
222 	usbser_power		/* devo_power */
223 };
224 
225 extern struct mod_ops mod_driverops;
226 
227 static struct modldrv modldrv = {
228 	&mod_driverops,		/* type of module - driver */
229 	"USB keyspan usb2serial driver %I%",
230 	&usbser_keyspan_ops,
231 };
232 
233 static struct modlinkage modlinkage = {
234 	MODREV_1, &modldrv, 0
235 };
236 
237 /* debug support */
238 static uint_t	keyspan_pre_errlevel = USB_LOG_L4;
239 static uint_t	keyspan_pre_errmask = DPRINT_MASK_ALL;
240 static uint_t	keyspan_pre_instance_debug = (uint_t)-1;
241 
242 /* firmware support for usa49wlc model */
243 extern usbser_keyspan_fw_record_t *keyspan_usa49wlc_fw(void);
244 #pragma weak keyspan_usa49wlc_fw
245 
246 /*
247  * configuration entry points
248  * --------------------------
249  */
250 int
251 _init(void)
252 {
253 	int    error;
254 
255 	if ((error = mod_install(&modlinkage)) == 0) {
256 		error = ddi_soft_state_init(&usbser_keyspan_statep,
257 		    max(usbser_soft_state_size(),
258 		    sizeof (keyspan_pre_state_t)), 1);
259 	}
260 
261 	return (error);
262 }
263 
264 
265 int
266 _fini(void)
267 {
268 	int    error;
269 
270 	if ((error = mod_remove(&modlinkage)) == 0) {
271 		ddi_soft_state_fini(&usbser_keyspan_statep);
272 	}
273 
274 	return (error);
275 }
276 
277 
278 int
279 _info(struct modinfo *modinfop)
280 {
281 	return (mod_info(&modlinkage, modinfop));
282 }
283 
284 
285 /*ARGSUSED*/
286 int
287 usbser_keyspan_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
288 		void **result)
289 {
290 	return (usbser_getinfo(dip, infocmd, arg, result,
291 	    usbser_keyspan_statep));
292 }
293 
294 
295 static int
296 usbser_keyspan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
297 {
298 	int	rval;
299 
300 	/*
301 	 * Once the device is plugged, we need set its cfg. And need download
302 	 * firmware for some of them.
303 	 */
304 	rval = keyspan_pre_attach(dip, cmd, usbser_keyspan_statep);
305 
306 	/*
307 	 * After the cfg is set, and the firmware is downloaded,
308 	 * do the real attach.
309 	 */
310 	if (rval == DDI_ECONTEXT) {
311 
312 		return (usbser_attach(dip, cmd, usbser_keyspan_statep,
313 		    &ds_ops));
314 	} else {
315 
316 		return (rval);
317 	}
318 }
319 
320 
321 static int
322 usbser_keyspan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
323 {
324 
325 	if (ddi_get_driver_private(dip) == NULL) {
326 
327 		return (keyspan_pre_detach(dip, cmd, usbser_keyspan_statep));
328 	} else {
329 
330 
331 		return (usbser_detach(dip, cmd, usbser_keyspan_statep));
332 
333 
334 	}
335 
336 }
337 
338 
339 static int
340 usbser_keyspan_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
341 {
342 	return (usbser_open(rq, dev, flag, sflag, cr, usbser_keyspan_statep));
343 }
344 
345 /*
346  * Switch config or download firmware
347  */
348 /*ARGSUSED*/
349 static int
350 keyspan_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, void *statep)
351 {
352 
353 	int			instance = ddi_get_instance(dip);
354 	keyspan_pre_state_t	*kbp = NULL;
355 	usb_client_dev_data_t	*dev_data = NULL;
356 	int			rval = DDI_FAILURE;
357 
358 	switch (cmd) {
359 	case DDI_ATTACH:
360 
361 		break;
362 	case DDI_RESUME:
363 
364 		return (DDI_SUCCESS);
365 	default:
366 
367 		return (DDI_FAILURE);
368 	}
369 
370 	/* attach driver to USBA */
371 	if (usb_client_attach(dip, USBDRV_VERSION, 0) == USB_SUCCESS) {
372 		(void) usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0);
373 	}
374 	if (dev_data == NULL) {
375 
376 		goto fail;
377 	}
378 
379 	/*
380 	 * If 19HS, needn't download firmware, but need check the current cfg.
381 	 * If 49WLC, need check the current cfg before download fw. And after
382 	 * download, the product id will change to KEYSPAN_USA49WLC_PID.
383 	 */
384 	if (dev_data->dev_descr->idProduct == KEYSPAN_USA19HS_PID ||
385 	    dev_data->dev_descr->idProduct == KEYSPAN_USA49WLC_PID) {
386 		if (keyspan_set_cfg(dip) == USB_SUCCESS) {
387 			/* Go to keyspan_attach() by return DDI_ECONTEXT. */
388 			rval =	DDI_ECONTEXT;
389 		}
390 
391 		goto fail;
392 	}
393 
394 	/*
395 	 * By checking KEYSPAN_FW_FLAG,  we can check whether the firmware
396 	 * has been downloaded.
397 	 * If firmware is already there, then do normal attach.
398 	 */
399 	if (!keyspan_need_fw(dev_data)) {
400 		/* Go to keyspan_attach() by return DDI_ECONTEXT. */
401 		rval =	DDI_ECONTEXT;
402 
403 		goto fail;
404 	}
405 
406 	/* Go on to download firmware. */
407 
408 	if (ddi_soft_state_zalloc(statep, instance) == DDI_SUCCESS) {
409 		kbp = ddi_get_soft_state(statep, instance);
410 	}
411 	if (kbp) {
412 		kbp->kb_dip = dip;
413 		kbp->kb_instance = instance;
414 		kbp->kb_dev_data = dev_data;
415 		kbp->kb_def_pipe.pipe_handle = kbp->kb_dev_data->dev_default_ph;
416 		kbp->kb_lh = usb_alloc_log_hdl(kbp->kb_dip, "keyspan[*].",
417 		    &keyspan_pre_errlevel, &keyspan_pre_errmask,
418 		    &keyspan_pre_instance_debug, 0);
419 
420 		kbp->kb_def_pipe.pipe_lh = kbp->kb_lh;
421 
422 		if (keyspan_download_firmware(kbp) == USB_SUCCESS) {
423 			USB_DPRINTF_L4(DPRINT_ATTACH, kbp->kb_lh,
424 			    "keyspan_pre_attach: completed.");
425 
426 			/* keyspan download firmware done. */
427 
428 			return (DDI_SUCCESS);
429 		}
430 	}
431 fail:
432 	if (kbp) {
433 		usb_free_log_hdl(kbp->kb_lh);
434 		ddi_soft_state_free(statep, instance);
435 	}
436 	usb_client_detach(dip, dev_data);
437 
438 	return (rval);
439 }
440 
441 
442 static int
443 keyspan_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, void *statep)
444 {
445 	int		instance = ddi_get_instance(dip);
446 	keyspan_pre_state_t	*kbp;
447 
448 	kbp = ddi_get_soft_state(statep, instance);
449 
450 	switch (cmd) {
451 	case DDI_DETACH:
452 
453 		break;
454 	case DDI_SUSPEND:
455 
456 		return (DDI_SUCCESS);
457 	default:
458 
459 		return (DDI_FAILURE);
460 	}
461 
462 	usb_free_log_hdl(kbp->kb_lh);
463 	usb_client_detach(dip, kbp->kb_dev_data);
464 	ddi_soft_state_free(statep, instance);
465 
466 	return (DDI_SUCCESS);
467 }
468 
469 
470 /* Set cfg for the device which has more than one cfg */
471 static int
472 keyspan_set_cfg(dev_info_t *dip)
473 {
474 
475 	if (usb_set_cfg(dip, 1, USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS) {
476 
477 		return (USB_FAILURE);
478 	}
479 
480 	return (USB_SUCCESS);
481 }
482 
483 
484 /* Return TRUE if need download firmware to the device. */
485 static boolean_t
486 keyspan_need_fw(usb_client_dev_data_t *dev_data)
487 {
488 	uint16_t	bcd_descr;
489 	uint16_t	bcd_descr_change;
490 
491 	/* need to convert to Little-Endian */
492 	bcd_descr = dev_data->dev_descr->bcdDevice;
493 
494 	/*
495 	 * According to Keyspan's interface spec, this flag indicates
496 	 * if need download fw.
497 	 */
498 	bcd_descr_change = bcd_descr & KEYSPAN_FW_FLAG;
499 
500 	return (bcd_descr_change == KEYSPAN_FW_FLAG);
501 }
502 
503 /* Set the device's register. */
504 static int
505 keyspan_set_reg(keyspan_pipe_t *pipe, uchar_t bit)
506 {
507 	int	rval;
508 
509 	/*
510 	 * (0x7f92) is the reg addr we want to set.
511 	 * We set this reg before/after downloading firmware.
512 	 */
513 	rval = keyspan_write_memory(pipe, 0x7f92, &bit, 1, KEYSPAN_REQ_SET);
514 
515 	return (rval);
516 }
517 
518 /*
519  * Download firmware or set register to the device by default ctrl pipe
520  */
521 static int
522 keyspan_write_memory(keyspan_pipe_t *pipe, uint16_t addr, uchar_t *buf,
523     uint16_t len, uint8_t bRequest)
524 {
525 	mblk_t *data;
526 	usb_ctrl_setup_t setup;
527 
528 	usb_cb_flags_t	cb_flags;
529 	usb_cr_t	cr;
530 	uint8_t		retry = 0;
531 
532 	/* reuse previous mblk if possible */
533 	if ((data = allocb(len, BPRI_HI)) == NULL) {
534 
535 		return (USB_FAILURE);
536 	}
537 
538 	bcopy(buf, data->b_rptr, len);
539 
540 	setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR;
541 
542 	/* This is a req defined by hardware vendor. */
543 	setup.bRequest = bRequest;
544 	setup.wValue = addr;
545 	setup.wIndex = 0;
546 	setup.wLength = len;
547 	setup.attrs = 0;
548 
549 	while (usb_pipe_ctrl_xfer_wait(pipe->pipe_handle, &setup, &data,
550 			&cr, &cb_flags, 0) != USB_SUCCESS) {
551 
552 		/* KEYSPAN_RETRY */
553 		if (++retry > 3) {
554 			if (data) {
555 				freemsg(data);
556 			}
557 
558 			return (USB_FAILURE);
559 		}
560 	}
561 
562 	if (data) {
563 		freemsg(data);
564 	}
565 
566 	return (USB_SUCCESS);
567 }
568 
569 /* Download firmware into device */
570 static int
571 keyspan_download_firmware(keyspan_pre_state_t *kbp)
572 {
573 	usbser_keyspan_fw_record_t *record = NULL;
574 
575 	/* If the firmware module exists, then download it to device. */
576 	if (&keyspan_usa49wlc_fw) {
577 
578 		record = keyspan_usa49wlc_fw();
579 	}
580 
581 	if (!record) {
582 		USB_DPRINTF_L1(DPRINT_ATTACH, kbp->kb_lh,
583 		    "No firmware available for Keyspan usa49wlc"
584 		    " usb-to-serial adapter. Refer to usbsksp(7D)"
585 		    " for details.");
586 
587 		return (USB_FAILURE);
588 	}
589 
590 	/* Set bit 1 before downloading firmware. */
591 	if (keyspan_set_reg(&kbp->kb_def_pipe, 1) != USB_SUCCESS) {
592 		USB_DPRINTF_L2(DPRINT_ATTACH, kbp->kb_lh,
593 		    "keyspan_pre_attach: Set register failed.");
594 
595 		return (USB_FAILURE);
596 	}
597 
598 	/* Write until the last record of the firmware */
599 	while (record->address != 0xffff) {
600 		if (keyspan_write_memory(&kbp->kb_def_pipe,
601 		    record->address, (uchar_t *)record->data,
602 		    record->data_len, KEYSPAN_REQ_SET) != USB_SUCCESS) {
603 			USB_DPRINTF_L2(DPRINT_ATTACH, kbp->kb_lh,
604 			    "keyspan_pre_attach: download firmware failed.");
605 
606 			return (USB_FAILURE);
607 		}
608 		record++;
609 	}
610 
611 	/*
612 	 * Set bit 0, device will be enumerated again after a while,
613 	 * and then go to keyspan_attach()
614 	 */
615 	if (keyspan_set_reg(&kbp->kb_def_pipe, 0) != USB_SUCCESS) {
616 
617 		return (USB_FAILURE);
618 	}
619 
620 	return (USB_SUCCESS);
621 }
622