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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * av1394 driver
29 */
30
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/cred.h>
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/stat.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39
40 #include <sys/1394/targets/av1394/av1394_impl.h>
41
42 /* DDI/DKI entry points */
43 static int av1394_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
44 static int av1394_attach(dev_info_t *, ddi_attach_cmd_t);
45 static int av1394_detach(dev_info_t *, ddi_detach_cmd_t);
46 static int av1394_open(dev_t *, int, int, cred_t *);
47 static int av1394_close(dev_t, int, int, cred_t *);
48 static int av1394_read(dev_t, struct uio *, cred_t *);
49 static int av1394_write(dev_t, struct uio *, cred_t *);
50 static int av1394_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
51 static int av1394_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
52 size_t *, uint_t);
53 static int av1394_poll(dev_t, short, int, short *, struct pollhead **);
54
55 /* configuration routines */
56 static void av1394_cleanup(av1394_inst_t *, int);
57 static int av1394_t1394_attach(av1394_inst_t *, dev_info_t *);
58 static void av1394_t1394_detach(av1394_inst_t *);
59 static int av1394_add_events(av1394_inst_t *);
60 static void av1394_remove_events(av1394_inst_t *);
61
62 /* CPR */
63 static int av1394_cpr_suspend(av1394_inst_t *);
64 static int av1394_cpr_resume(av1394_inst_t *);
65
66 /* callbacks */
67 static void av1394_bus_reset(dev_info_t *, ddi_eventcookie_t, void *,
68 void *);
69 static void av1394_disconnect(dev_info_t *, ddi_eventcookie_t, void *,
70 void *);
71 static void av1394_reconnect(dev_info_t *, ddi_eventcookie_t, void *,
72 void *);
73
74 extern struct mod_ops mod_driverops;
75
76 struct cb_ops av1394_cb_ops = {
77 av1394_open, /* open */
78 av1394_close, /* close */
79 nulldev, /* strategy */
80 nulldev, /* print */
81 nulldev, /* dump */
82 av1394_read, /* read */
83 av1394_write, /* write */
84 av1394_ioctl, /* ioctl */
85 av1394_devmap, /* devmap */
86 nulldev, /* mmap */
87 nulldev, /* segmap */
88 av1394_poll, /* poll */
89 ddi_prop_op, /* cb_prop_op */
90 NULL, /* streamtab */
91 D_MP | D_NEW | D_HOTPLUG | D_DEVMAP
92 };
93
94 static struct dev_ops av1394_ops = {
95 DEVO_REV, /* devo_rev */
96 0, /* refcnt */
97 av1394_getinfo, /* getinfo */
98 nulldev, /* identify */
99 nulldev, /* probe */
100 av1394_attach, /* attach */
101 av1394_detach, /* detach */
102 nodev, /* reset */
103 &av1394_cb_ops, /* driver operations */
104 NULL, /* bus operations */
105 NULL, /* power */
106 ddi_quiesce_not_supported, /* devo_quiesce */
107 };
108
109 static struct modldrv av1394_modldrv = {
110 &mod_driverops,
111 "IEEE 1394 AV driver",
112 &av1394_ops
113 };
114
115 static struct modlinkage av1394_modlinkage = {
116 MODREV_1,
117 &av1394_modldrv,
118 NULL,
119 };
120
121 static void *av1394_statep;
122
123 #ifndef NPROBE
124 extern int tnf_mod_load(void);
125 extern int tnf_mod_unload(struct modlinkage *mlp);
126 #endif
127
128 #define AV1394_INST2STATE(inst) (ddi_get_soft_state(av1394_statep, inst))
129 #define AV1394_DEV2STATE(dev) \
130 (ddi_get_soft_state(av1394_statep, AV1394_DEV2INST(dev)))
131
132 #define AV1394_TNF_ENTER(func) \
133 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_INST_STACK, "");
134
135 #define AV1394_TNF_EXIT(func) \
136 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_INST_STACK, "");
137
138 /*
139 *
140 * --- DDI/DKI entry points
141 *
142 */
143 int
144 _init(void)
145 {
146 int error;
147
148 #ifndef NPROBE
149 (void) tnf_mod_load();
150 #endif
151 error = ddi_soft_state_init(&av1394_statep, sizeof (av1394_inst_t), 1);
152 if (error != 0) {
153 #ifndef NPROBE
154 (void) tnf_mod_unload(&av1394_modlinkage);
155 #endif
156 return (error);
157 }
158
159 if ((error = mod_install(&av1394_modlinkage)) != 0) {
160 ddi_soft_state_fini(&av1394_statep);
161 #ifndef NPROBE
162 (void) tnf_mod_unload(&av1394_modlinkage);
163 #endif
164 }
165
166 return (error);
167 }
168
169 int
170 _fini(void)
171 {
172 int error;
173
174 if ((error = mod_remove(&av1394_modlinkage)) == 0) {
175 ddi_soft_state_fini(&av1394_statep);
176 #ifndef NPROBE
177 (void) tnf_mod_unload(&av1394_modlinkage);
178 #endif
179 }
180
181 return (error);
182 }
183
184 int
185 _info(struct modinfo *modinfop)
186 {
187 return (mod_info(&av1394_modlinkage, modinfop));
188 }
189
190 /*
191 * attach
192 */
193 static int
194 av1394_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
195 {
196 int instance = ddi_get_instance(dip);
197 av1394_inst_t *avp;
198
199 AV1394_TNF_ENTER(av1394_attach);
200
201 switch (cmd) {
202 case DDI_ATTACH:
203 break;
204 case DDI_RESUME:
205 if ((avp = AV1394_INST2STATE(instance)) == NULL) {
206 return (DDI_FAILURE);
207 }
208 return (av1394_cpr_resume(avp));
209 default:
210 AV1394_TNF_EXIT(av1394_attach);
211 return (DDI_FAILURE);
212 }
213
214 if (ddi_soft_state_zalloc(av1394_statep, instance) != 0) {
215 TNF_PROBE_0(av1394_attach_error_soft_state_zalloc,
216 AV1394_TNF_INST_ERROR, "");
217 AV1394_TNF_EXIT(av1394_attach);
218 return (DDI_FAILURE);
219 }
220 avp = AV1394_INST2STATE(instance);
221
222 if (av1394_t1394_attach(avp, dip) != DDI_SUCCESS) {
223 av1394_cleanup(avp, 1);
224 AV1394_TNF_EXIT(av1394_attach);
225 return (DDI_FAILURE);
226 }
227
228 mutex_init(&avp->av_mutex, NULL, MUTEX_DRIVER,
229 avp->av_attachinfo.iblock_cookie);
230
231 avp->av_dip = dip;
232 avp->av_instance = instance;
233
234 if (av1394_add_events(avp) != DDI_SUCCESS) {
235 av1394_cleanup(avp, 2);
236 AV1394_TNF_EXIT(av1394_attach);
237 return (DDI_FAILURE);
238 }
239
240 if (av1394_isoch_attach(avp) != DDI_SUCCESS) {
241 av1394_cleanup(avp, 3);
242 AV1394_TNF_EXIT(av1394_attach);
243 return (DDI_FAILURE);
244 }
245
246 if (av1394_async_attach(avp) != DDI_SUCCESS) {
247 av1394_cleanup(avp, 4);
248 AV1394_TNF_EXIT(av1394_attach);
249 return (DDI_FAILURE);
250 }
251
252 avp->av_dev_state = AV1394_DEV_ONLINE;
253
254 ddi_report_dev(dip);
255
256 AV1394_TNF_EXIT(av1394_attach);
257 return (DDI_SUCCESS);
258 }
259
260 static int
261 av1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
262 {
263 int instance = ddi_get_instance(dip);
264 av1394_inst_t *avp;
265
266 AV1394_TNF_ENTER(av1394_detach);
267
268 if ((avp = AV1394_INST2STATE(instance)) == NULL) {
269 TNF_PROBE_0(av1394_detach_error_instance,
270 AV1394_TNF_INST_ERROR, "");
271 AV1394_TNF_EXIT(av1394_detach);
272 return (DDI_FAILURE);
273 }
274
275 switch (cmd) {
276 case DDI_DETACH:
277 av1394_cleanup(avp, AV1394_CLEANUP_LEVEL_MAX);
278 AV1394_TNF_EXIT(av1394_detach);
279 return (DDI_SUCCESS);
280 case DDI_SUSPEND:
281 return (av1394_cpr_suspend(avp));
282 default:
283 AV1394_TNF_EXIT(av1394_detach);
284 return (DDI_FAILURE);
285 }
286 }
287
288 /*ARGSUSED*/
289 static int
290 av1394_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
291 void **result)
292 {
293 dev_t dev = (dev_t)arg;
294 av1394_inst_t *avp;
295 int rval = DDI_FAILURE;
296
297 switch (infocmd) {
298 case DDI_INFO_DEVT2DEVINFO:
299 if ((avp = AV1394_DEV2STATE(dev)) != NULL) {
300 *result = avp->av_dip;
301 rval = DDI_SUCCESS;
302 } else {
303 *result = NULL;
304 }
305 break;
306 case DDI_INFO_DEVT2INSTANCE:
307 *result = (void *)(uintptr_t)AV1394_DEV2INST(dev);
308 rval = DDI_SUCCESS;
309 break;
310 }
311
312 return (rval);
313 }
314
315 /*ARGSUSED*/
316 static int
317 av1394_open(dev_t *dev, int flag, int otyp, cred_t *cr)
318 {
319 av1394_inst_t *avp = AV1394_DEV2STATE(*dev);
320 int ret = ENXIO;
321
322 AV1394_TNF_ENTER(av1394_open);
323 if (avp != NULL) {
324 if (AV1394_DEV_IS_ISOCH(*dev)) {
325 ret = 0;
326 } else if (AV1394_DEV_IS_ASYNC(*dev)) {
327 ret = av1394_async_open(avp, flag);
328 }
329 }
330 AV1394_TNF_EXIT(av1394_open);
331 return (ret);
332 }
333
334 /*ARGSUSED*/
335 static int
336 av1394_close(dev_t dev, int flag, int otyp, cred_t *cr)
337 {
338 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
339 int ret = ENXIO;
340
341 AV1394_TNF_ENTER(av1394_close);
342 if (avp != NULL) {
343 if (AV1394_DEV_IS_ISOCH(dev)) {
344 ret = av1394_isoch_close(avp, flag);
345 } else if (AV1394_DEV_IS_ASYNC(dev)) {
346 ret = av1394_async_close(avp, flag);
347 }
348 }
349 AV1394_TNF_EXIT(av1394_close);
350 return (ret);
351 }
352
353 /*ARGSUSED*/
354 static int
355 av1394_read(dev_t dev, struct uio *uiop, cred_t *cr)
356 {
357 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
358 int ret = ENXIO;
359
360 AV1394_TNF_ENTER(av1394_read);
361 if (avp != NULL) {
362 if (AV1394_DEV_IS_ISOCH(dev)) {
363 ret = av1394_isoch_read(avp, uiop);
364 } else if (AV1394_DEV_IS_ASYNC(dev)) {
365 ret = av1394_async_read(avp, uiop);
366 }
367 }
368 AV1394_TNF_EXIT(av1394_read);
369 return (ret);
370 }
371
372 /*ARGSUSED*/
373 static int
374 av1394_write(dev_t dev, struct uio *uiop, cred_t *cr)
375 {
376 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
377 int ret = ENXIO;
378
379 AV1394_TNF_ENTER(av1394_write);
380 if (avp != NULL) {
381 if (AV1394_DEV_IS_ISOCH(dev)) {
382 ret = av1394_isoch_write(avp, uiop);
383 } else if (AV1394_DEV_IS_ASYNC(dev)) {
384 ret = av1394_async_write(avp, uiop);
385 }
386 }
387 AV1394_TNF_EXIT(av1394_write);
388 return (ret);
389 }
390
391 /*ARGSUSED*/
392 static int
393 av1394_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp)
394 {
395 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
396 int ret = ENXIO;
397
398 AV1394_TNF_ENTER(av1394_ioctl);
399 if (avp != NULL) {
400 if (AV1394_DEV_IS_ISOCH(dev)) {
401 ret = av1394_isoch_ioctl(avp, cmd, arg, mode, rvalp);
402 } else if (AV1394_DEV_IS_ASYNC(dev)) {
403 ret = av1394_async_ioctl(avp, cmd, arg, mode, rvalp);
404 }
405 }
406 AV1394_TNF_EXIT(av1394_ioctl);
407 return (ret);
408 }
409
410 /*ARGSUSED*/
411 static int
412 av1394_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
413 size_t *maplen, uint_t model)
414 {
415 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
416 int ret = ENXIO;
417
418 AV1394_TNF_ENTER(av1394_devmap);
419 if ((avp != NULL) && (AV1394_DEV_IS_ISOCH(dev))) {
420 ret = av1394_isoch_devmap(avp, dhp, off, len, maplen, model);
421 }
422 AV1394_TNF_EXIT(av1394_devmap);
423 return (ret);
424 }
425
426 static int
427 av1394_poll(dev_t dev, short events, int anyyet, short *reventsp,
428 struct pollhead **phpp)
429 {
430 av1394_inst_t *avp = AV1394_DEV2STATE(dev);
431 int ret = ENXIO;
432
433 AV1394_TNF_ENTER(av1394_poll);
434 if ((avp != NULL) && AV1394_DEV_IS_ASYNC(dev)) {
435 ret = av1394_async_poll(avp, events, anyyet, reventsp, phpp);
436 }
437 AV1394_TNF_EXIT(av1394_poll);
438 return (ret);
439 }
440
441
442 /*
443 *
444 * --- configuration routines
445 *
446 * av1394_cleanup()
447 * Cleanup after attach
448 */
449 static void
450 av1394_cleanup(av1394_inst_t *avp, int level)
451 {
452 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
453
454 AV1394_TNF_ENTER(av1394_cleanup);
455 switch (level) {
456 default:
457 av1394_async_detach(avp);
458 /* FALLTHRU */
459 case 4:
460 av1394_isoch_detach(avp);
461 /* FALLTHRU */
462 case 3:
463 av1394_remove_events(avp);
464 /* FALLTHRU */
465 case 2:
466 av1394_t1394_detach(avp);
467 mutex_destroy(&avp->av_mutex);
468 /* FALLTHRU */
469 case 1:
470 ddi_soft_state_free(av1394_statep, avp->av_instance);
471 }
472 AV1394_TNF_EXIT(av1394_cleanup);
473 }
474
475 static int
476 av1394_t1394_attach(av1394_inst_t *avp, dev_info_t *dip)
477 {
478 int ret;
479
480 AV1394_TNF_ENTER(av1394_t1394_attach);
481
482 ret = t1394_attach(dip, T1394_VERSION_V1, 0, &avp->av_attachinfo,
483 &avp->av_t1394_hdl);
484
485 if (ret != DDI_SUCCESS) {
486 TNF_PROBE_1(av1394_t1394_attach_error, AV1394_TNF_INST_ERROR,
487 "", tnf_int, ret, ret);
488 }
489
490 AV1394_TNF_EXIT(av1394_t1394_attach);
491 return (ret);
492 }
493
494 static void
495 av1394_t1394_detach(av1394_inst_t *avp)
496 {
497 AV1394_TNF_ENTER(av1394_t1394_detach);
498
499 (void) t1394_detach(&avp->av_t1394_hdl, 0);
500
501 AV1394_TNF_EXIT(av1394_t1394_detach);
502 }
503
504 static int
505 av1394_add_events(av1394_inst_t *avp)
506 {
507 ddi_eventcookie_t br_evc, rem_evc, ins_evc;
508
509 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT,
510 &br_evc) != DDI_SUCCESS) {
511 TNF_PROBE_0(av1394_add_events_error_bus_reset_cookie,
512 AV1394_TNF_INST_ERROR, "");
513 return (DDI_FAILURE);
514 }
515 if (ddi_add_event_handler(avp->av_dip, br_evc, av1394_bus_reset,
516 avp, &avp->av_reset_cb) != DDI_SUCCESS) {
517 TNF_PROBE_0(av1394_add_events_error_bus_reset_event,
518 AV1394_TNF_INST_ERROR, "");
519 return (DDI_FAILURE);
520 }
521
522 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT,
523 &rem_evc) != DDI_SUCCESS) {
524 (void) ddi_remove_event_handler(avp->av_reset_cb);
525 TNF_PROBE_0(av1394_add_events_error_remove_cookie,
526 AV1394_TNF_INST_ERROR, "");
527 return (DDI_FAILURE);
528 }
529 if (ddi_add_event_handler(avp->av_dip, rem_evc, av1394_disconnect,
530 avp, &avp->av_remove_cb) != DDI_SUCCESS) {
531 (void) ddi_remove_event_handler(avp->av_reset_cb);
532 TNF_PROBE_0(av1394_add_events_error_remove_event,
533 AV1394_TNF_INST_ERROR, "");
534 return (DDI_FAILURE);
535 }
536
537 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT,
538 &ins_evc) != DDI_SUCCESS) {
539 (void) ddi_remove_event_handler(avp->av_remove_cb);
540 (void) ddi_remove_event_handler(avp->av_reset_cb);
541 TNF_PROBE_0(av1394_add_events_error_insert_cookie,
542 AV1394_TNF_INST_ERROR, "");
543 return (DDI_FAILURE);
544 }
545 if (ddi_add_event_handler(avp->av_dip, ins_evc, av1394_reconnect,
546 avp, &avp->av_insert_cb) != DDI_SUCCESS) {
547 (void) ddi_remove_event_handler(avp->av_remove_cb);
548 (void) ddi_remove_event_handler(avp->av_reset_cb);
549 TNF_PROBE_0(av1394_add_events_error_insert_event,
550 AV1394_TNF_INST_ERROR, "");
551 return (DDI_FAILURE);
552 }
553
554 return (DDI_SUCCESS);
555 }
556
557 static void
558 av1394_remove_events(av1394_inst_t *avp)
559 {
560 ddi_eventcookie_t evc;
561
562 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT,
563 &evc) == DDI_SUCCESS) {
564 (void) ddi_remove_event_handler(avp->av_insert_cb);
565 }
566
567 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT,
568 &evc) == DDI_SUCCESS) {
569 (void) ddi_remove_event_handler(avp->av_remove_cb);
570 }
571
572 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT,
573 &evc) == DDI_SUCCESS) {
574 (void) ddi_remove_event_handler(avp->av_reset_cb);
575 }
576 }
577
578 /*
579 *
580 * --- CPR
581 *
582 */
583 static int
584 av1394_cpr_suspend(av1394_inst_t *avp)
585 {
586 int ret;
587
588 AV1394_TNF_ENTER(av1394_cpr_suspend);
589
590 ret = av1394_isoch_cpr_suspend(avp);
591
592 if (ret == DDI_SUCCESS) {
593 mutex_enter(&avp->av_mutex);
594 avp->av_prev_dev_state = avp->av_dev_state;
595 avp->av_dev_state = AV1394_DEV_SUSPENDED;
596 mutex_exit(&avp->av_mutex);
597 }
598
599 AV1394_TNF_EXIT(av1394_cpr_suspend);
600 return (ret);
601 }
602
603 /*
604 * CPR resume should always succeed
605 */
606 static int
607 av1394_cpr_resume(av1394_inst_t *avp)
608 {
609 AV1394_TNF_ENTER(av1394_cpr_resume);
610
611 mutex_enter(&avp->av_mutex);
612 avp->av_dev_state = avp->av_prev_dev_state;
613 mutex_exit(&avp->av_mutex);
614
615 (void) av1394_async_cpr_resume(avp);
616
617 AV1394_TNF_EXIT(av1394_cpr_resume);
618 return (DDI_SUCCESS);
619 }
620
621 /*
622 *
623 * --- callbacks
624 *
625 */
626 /*ARGSUSED*/
627 static void
628 av1394_bus_reset(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data)
629 {
630 av1394_inst_t *avp = arg;
631
632 AV1394_TNF_ENTER(av1394_bus_reset);
633
634 if (avp == NULL) {
635 AV1394_TNF_EXIT(av1394_bus_reset);
636 return;
637 }
638
639 mutex_enter(&avp->av_mutex);
640 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data;
641 mutex_exit(&avp->av_mutex);
642
643 av1394_async_bus_reset(avp);
644 av1394_cmp_bus_reset(avp);
645
646 AV1394_TNF_EXIT(av1394_bus_reset);
647 }
648
649 /*ARGSUSED*/
650 static void
651 av1394_disconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data)
652 {
653 av1394_inst_t *avp = arg;
654
655 AV1394_TNF_ENTER(av1394_disconnect);
656
657 if (avp == NULL) {
658 AV1394_TNF_EXIT(av1394_disconnect);
659 return;
660 }
661
662 mutex_enter(&avp->av_mutex);
663 avp->av_dev_state = AV1394_DEV_DISCONNECTED;
664 mutex_exit(&avp->av_mutex);
665
666 AV1394_TNF_EXIT(av1394_disconnect);
667 }
668
669 /*ARGSUSED*/
670 static void
671 av1394_reconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data)
672 {
673 av1394_inst_t *avp = arg;
674
675 AV1394_TNF_ENTER(av1394_disconnect);
676
677 if (avp == NULL) {
678 AV1394_TNF_EXIT(av1394_disconnect);
679 return;
680 }
681
682 mutex_enter(&avp->av_mutex);
683 avp->av_dev_state = AV1394_DEV_ONLINE;
684 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data;
685 mutex_exit(&avp->av_mutex);
686
687 av1394_async_reconnect(avp);
688
689 AV1394_TNF_EXIT(av1394_disconnect);
690 }