libusb10_io.c revision 236944
1/* $FreeBSD: head/lib/libusb/libusb10_io.c 236944 2012-06-12 07:28:25Z hselasky $ */
2/*-
3 * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/queue.h>
28
29#include <errno.h>
30#include <poll.h>
31#include <pthread.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <time.h>
35#include <unistd.h>
36
37#define	libusb_device_handle libusb20_device
38
39#include "libusb20.h"
40#include "libusb20_desc.h"
41#include "libusb20_int.h"
42#include "libusb.h"
43#include "libusb10.h"
44
45UNEXPORTED void
46libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
47    struct libusb20_device *pdev, int fd, short events)
48{
49	if (ctx == NULL)
50		return;			/* invalid */
51
52	if (pollfd->entry.tqe_prev != NULL)
53		return;			/* already queued */
54
55	if (fd < 0)
56		return;			/* invalid */
57
58	pollfd->pdev = pdev;
59	pollfd->pollfd.fd = fd;
60	pollfd->pollfd.events = events;
61
62	CTX_LOCK(ctx);
63	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
64	CTX_UNLOCK(ctx);
65
66	if (ctx->fd_added_cb)
67		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
68}
69
70UNEXPORTED void
71libusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
72{
73	if (ctx == NULL)
74		return;			/* invalid */
75
76	if (pollfd->entry.tqe_prev == NULL)
77		return;			/* already dequeued */
78
79	CTX_LOCK(ctx);
80	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
81	pollfd->entry.tqe_prev = NULL;
82	CTX_UNLOCK(ctx);
83
84	if (ctx->fd_removed_cb)
85		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
86}
87
88/* This function must be called locked */
89
90static int
91libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
92{
93	struct libusb_device *dev;
94	struct libusb20_device **ppdev;
95	struct libusb_super_pollfd *pfd;
96	struct pollfd *fds;
97	struct libusb_super_transfer *sxfer;
98	struct libusb_transfer *uxfer;
99	nfds_t nfds;
100	int timeout;
101	int i;
102	int err;
103
104	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
105
106	nfds = 0;
107	i = 0;
108	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
109	    nfds++;
110
111	fds = alloca(sizeof(*fds) * nfds);
112	if (fds == NULL)
113		return (LIBUSB_ERROR_NO_MEM);
114
115	ppdev = alloca(sizeof(*ppdev) * nfds);
116	if (ppdev == NULL)
117		return (LIBUSB_ERROR_NO_MEM);
118
119	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
120		fds[i].fd = pfd->pollfd.fd;
121		fds[i].events = pfd->pollfd.events;
122		fds[i].revents = 0;
123		ppdev[i] = pfd->pdev;
124		if (pfd->pdev != NULL)
125			libusb_get_device(pfd->pdev)->refcnt++;
126		i++;
127	}
128
129	if (tv == NULL)
130		timeout = -1;
131	else
132		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
133
134	CTX_UNLOCK(ctx);
135	err = poll(fds, nfds, timeout);
136	CTX_LOCK(ctx);
137
138	if ((err == -1) && (errno == EINTR))
139		err = LIBUSB_ERROR_INTERRUPTED;
140	else if (err < 0)
141		err = LIBUSB_ERROR_IO;
142
143	if (err < 1) {
144		for (i = 0; i != (int)nfds; i++) {
145			if (ppdev[i] != NULL) {
146				CTX_UNLOCK(ctx);
147				libusb_unref_device(libusb_get_device(ppdev[i]));
148				CTX_LOCK(ctx);
149			}
150		}
151		goto do_done;
152	}
153	for (i = 0; i != (int)nfds; i++) {
154		if (ppdev[i] != NULL) {
155			dev = libusb_get_device(ppdev[i]);
156
157			if (fds[i].revents == 0)
158				err = 0;	/* nothing to do */
159			else
160				err = libusb20_dev_process(ppdev[i]);
161
162			if (err) {
163				/* cancel all transfers - device is gone */
164				libusb10_cancel_all_transfer(dev);
165
166				/* remove USB device from polling loop */
167				libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
168			}
169			CTX_UNLOCK(ctx);
170			libusb_unref_device(dev);
171			CTX_LOCK(ctx);
172
173		} else {
174			uint8_t dummy;
175
176			while (1) {
177				if (read(fds[i].fd, &dummy, 1) != 1)
178					break;
179			}
180		}
181	}
182
183	err = 0;
184
185do_done:
186
187	/* Do all done callbacks */
188
189	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
190		uint8_t flags;
191
192		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
193		sxfer->entry.tqe_prev = NULL;
194
195		ctx->tr_done_ref++;
196
197		CTX_UNLOCK(ctx);
198
199		uxfer = (struct libusb_transfer *)(
200		    ((uint8_t *)sxfer) + sizeof(*sxfer));
201
202		/* Allow the callback to free the transfer itself. */
203		flags = uxfer->flags;
204
205		if (uxfer->callback != NULL)
206			(uxfer->callback) (uxfer);
207
208		/* Check if the USB transfer should be automatically freed. */
209		if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)
210			libusb_free_transfer(uxfer);
211
212		CTX_LOCK(ctx);
213
214		ctx->tr_done_ref--;
215		ctx->tr_done_gen++;
216	}
217
218	/* Wakeup other waiters */
219	pthread_cond_broadcast(&ctx->ctx_cond);
220
221	return (err);
222}
223
224/* Polling and timing */
225
226int
227libusb_try_lock_events(libusb_context *ctx)
228{
229	int err;
230
231	ctx = GET_CONTEXT(ctx);
232	if (ctx == NULL)
233		return (1);
234
235	err = CTX_TRYLOCK(ctx);
236	if (err)
237		return (1);
238
239	err = (ctx->ctx_handler != NO_THREAD);
240	if (err)
241		CTX_UNLOCK(ctx);
242	else
243		ctx->ctx_handler = pthread_self();
244
245	return (err);
246}
247
248void
249libusb_lock_events(libusb_context *ctx)
250{
251	ctx = GET_CONTEXT(ctx);
252	CTX_LOCK(ctx);
253	if (ctx->ctx_handler == NO_THREAD)
254		ctx->ctx_handler = pthread_self();
255}
256
257void
258libusb_unlock_events(libusb_context *ctx)
259{
260	ctx = GET_CONTEXT(ctx);
261	if (ctx->ctx_handler == pthread_self()) {
262		ctx->ctx_handler = NO_THREAD;
263		pthread_cond_broadcast(&ctx->ctx_cond);
264	}
265	CTX_UNLOCK(ctx);
266}
267
268int
269libusb_event_handling_ok(libusb_context *ctx)
270{
271	ctx = GET_CONTEXT(ctx);
272	return (ctx->ctx_handler == pthread_self());
273}
274
275int
276libusb_event_handler_active(libusb_context *ctx)
277{
278	ctx = GET_CONTEXT(ctx);
279	return (ctx->ctx_handler != NO_THREAD);
280}
281
282void
283libusb_lock_event_waiters(libusb_context *ctx)
284{
285	ctx = GET_CONTEXT(ctx);
286	CTX_LOCK(ctx);
287}
288
289void
290libusb_unlock_event_waiters(libusb_context *ctx)
291{
292	ctx = GET_CONTEXT(ctx);
293	CTX_UNLOCK(ctx);
294}
295
296int
297libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
298{
299	struct timespec ts;
300	int err;
301
302	ctx = GET_CONTEXT(ctx);
303	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
304
305	if (tv == NULL) {
306		pthread_cond_wait(&ctx->ctx_cond,
307		    &ctx->ctx_lock);
308		return (0);
309	}
310	err = clock_gettime(CLOCK_MONOTONIC, &ts);
311	if (err < 0)
312		return (LIBUSB_ERROR_OTHER);
313
314	/*
315	 * The "tv" arguments points to a relative time structure and
316	 * not an absolute time structure.
317	 */
318	ts.tv_sec += tv->tv_sec;
319	ts.tv_nsec += tv->tv_usec * 1000;
320	if (ts.tv_nsec >= 1000000000) {
321		ts.tv_nsec -= 1000000000;
322		ts.tv_sec++;
323	}
324	err = pthread_cond_timedwait(&ctx->ctx_cond,
325	    &ctx->ctx_lock, &ts);
326
327	if (err == ETIMEDOUT)
328		return (1);
329
330	return (0);
331}
332
333int
334libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
335{
336	int err;
337
338	ctx = GET_CONTEXT(ctx);
339
340	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
341
342	libusb_lock_events(ctx);
343
344	err = libusb_handle_events_locked(ctx, tv);
345
346	libusb_unlock_events(ctx);
347
348	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
349
350	return (err);
351}
352
353int
354libusb_handle_events(libusb_context *ctx)
355{
356	return (libusb_handle_events_timeout(ctx, NULL));
357}
358
359int
360libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
361{
362	int err;
363
364	ctx = GET_CONTEXT(ctx);
365
366	if (libusb_event_handling_ok(ctx)) {
367		err = libusb10_handle_events_sub(ctx, tv);
368	} else {
369		libusb_wait_for_event(ctx, tv);
370		err = 0;
371	}
372	return (err);
373}
374
375int
376libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
377{
378	/* all timeouts are currently being done by the kernel */
379	timerclear(tv);
380	return (0);
381}
382
383void
384libusb_set_pollfd_notifiers(libusb_context *ctx,
385    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
386    void *user_data)
387{
388	ctx = GET_CONTEXT(ctx);
389
390	ctx->fd_added_cb = added_cb;
391	ctx->fd_removed_cb = removed_cb;
392	ctx->fd_cb_user_data = user_data;
393}
394
395struct libusb_pollfd **
396libusb_get_pollfds(libusb_context *ctx)
397{
398	struct libusb_super_pollfd *pollfd;
399	libusb_pollfd **ret;
400	int i;
401
402	ctx = GET_CONTEXT(ctx);
403
404	CTX_LOCK(ctx);
405
406	i = 0;
407	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
408	    i++;
409
410	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
411	if (ret == NULL)
412		goto done;
413
414	i = 0;
415	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
416	    ret[i++] = &pollfd->pollfd;
417	ret[i] = NULL;
418
419done:
420	CTX_UNLOCK(ctx);
421	return (ret);
422}
423
424
425/* Synchronous device I/O */
426
427int
428libusb_control_transfer(libusb_device_handle *devh,
429    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
430    uint8_t *data, uint16_t wLength, unsigned int timeout)
431{
432	struct LIBUSB20_CONTROL_SETUP_DECODED req;
433	int err;
434	uint16_t actlen;
435
436	if (devh == NULL)
437		return (LIBUSB_ERROR_INVALID_PARAM);
438
439	if ((wLength != 0) && (data == NULL))
440		return (LIBUSB_ERROR_INVALID_PARAM);
441
442	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
443
444	req.bmRequestType = bmRequestType;
445	req.bRequest = bRequest;
446	req.wValue = wValue;
447	req.wIndex = wIndex;
448	req.wLength = wLength;
449
450	err = libusb20_dev_request_sync(devh, &req, data,
451	    &actlen, timeout, 0);
452
453	if (err == LIBUSB20_ERROR_PIPE)
454		return (LIBUSB_ERROR_PIPE);
455	else if (err == LIBUSB20_ERROR_TIMEOUT)
456		return (LIBUSB_ERROR_TIMEOUT);
457	else if (err)
458		return (LIBUSB_ERROR_NO_DEVICE);
459
460	return (actlen);
461}
462
463static void
464libusb10_do_transfer_cb(struct libusb_transfer *transfer)
465{
466	libusb_context *ctx;
467	int *pdone;
468
469	ctx = GET_CONTEXT(NULL);
470
471	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
472
473	pdone = transfer->user_data;
474	*pdone = 1;
475}
476
477/*
478 * TODO: Replace the following function. Allocating and freeing on a
479 * per-transfer basis is slow.  --HPS
480 */
481static int
482libusb10_do_transfer(libusb_device_handle *devh,
483    uint8_t endpoint, uint8_t *data, int length,
484    int *transferred, unsigned int timeout, int type)
485{
486	libusb_context *ctx;
487	struct libusb_transfer *xfer;
488	int done;
489	int ret;
490
491	if (devh == NULL)
492		return (LIBUSB_ERROR_INVALID_PARAM);
493
494	if ((length != 0) && (data == NULL))
495		return (LIBUSB_ERROR_INVALID_PARAM);
496
497	xfer = libusb_alloc_transfer(0);
498	if (xfer == NULL)
499		return (LIBUSB_ERROR_NO_MEM);
500
501	ctx = libusb_get_device(devh)->ctx;
502
503	xfer->dev_handle = devh;
504	xfer->endpoint = endpoint;
505	xfer->type = type;
506	xfer->timeout = timeout;
507	xfer->buffer = data;
508	xfer->length = length;
509	xfer->user_data = (void *)&done;
510	xfer->callback = libusb10_do_transfer_cb;
511	done = 0;
512
513	if ((ret = libusb_submit_transfer(xfer)) < 0) {
514		libusb_free_transfer(xfer);
515		return (ret);
516	}
517	while (done == 0) {
518		if ((ret = libusb_handle_events(ctx)) < 0) {
519			libusb_cancel_transfer(xfer);
520			usleep(1000);	/* nice it */
521		}
522	}
523
524	*transferred = xfer->actual_length;
525
526	switch (xfer->status) {
527	case LIBUSB_TRANSFER_COMPLETED:
528		ret = 0;
529		break;
530	case LIBUSB_TRANSFER_TIMED_OUT:
531		ret = LIBUSB_ERROR_TIMEOUT;
532		break;
533	case LIBUSB_TRANSFER_OVERFLOW:
534		ret = LIBUSB_ERROR_OVERFLOW;
535		break;
536	case LIBUSB_TRANSFER_STALL:
537		ret = LIBUSB_ERROR_PIPE;
538		break;
539	case LIBUSB_TRANSFER_NO_DEVICE:
540		ret = LIBUSB_ERROR_NO_DEVICE;
541		break;
542	default:
543		ret = LIBUSB_ERROR_OTHER;
544		break;
545	}
546
547	libusb_free_transfer(xfer);
548	return (ret);
549}
550
551int
552libusb_bulk_transfer(libusb_device_handle *devh,
553    uint8_t endpoint, uint8_t *data, int length,
554    int *transferred, unsigned int timeout)
555{
556	libusb_context *ctx;
557	int ret;
558
559	ctx = GET_CONTEXT(NULL);
560	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
561
562	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
563	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
564
565	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
566	return (ret);
567}
568
569int
570libusb_interrupt_transfer(libusb_device_handle *devh,
571    uint8_t endpoint, uint8_t *data, int length,
572    int *transferred, unsigned int timeout)
573{
574	libusb_context *ctx;
575	int ret;
576
577	ctx = GET_CONTEXT(NULL);
578	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
579
580	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
581	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
582
583	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
584	return (ret);
585}
586
587uint8_t *
588libusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off)
589{
590	uint8_t *ptr;
591	uint32_t n;
592
593	if (transfer->num_iso_packets < 0)
594		return (NULL);
595
596	if (off >= (uint32_t)transfer->num_iso_packets)
597		return (NULL);
598
599	ptr = transfer->buffer;
600	if (ptr == NULL)
601		return (NULL);
602
603	for (n = 0; n != off; n++) {
604		ptr += transfer->iso_packet_desc[n].length;
605	}
606	return (ptr);
607}
608
609uint8_t *
610libusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off)
611{
612	uint8_t *ptr;
613
614	if (transfer->num_iso_packets < 0)
615		return (NULL);
616
617	if (off >= (uint32_t)transfer->num_iso_packets)
618		return (NULL);
619
620	ptr = transfer->buffer;
621	if (ptr == NULL)
622		return (NULL);
623
624	ptr += transfer->iso_packet_desc[0].length * off;
625
626	return (ptr);
627}
628
629void
630libusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
631{
632	int n;
633
634	if (transfer->num_iso_packets < 0)
635		return;
636
637	for (n = 0; n != transfer->num_iso_packets; n++)
638		transfer->iso_packet_desc[n].length = length;
639}
640
641uint8_t *
642libusb_control_transfer_get_data(struct libusb_transfer *transfer)
643{
644	if (transfer->buffer == NULL)
645		return (NULL);
646
647	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
648}
649
650struct libusb_control_setup *
651libusb_control_transfer_get_setup(struct libusb_transfer *transfer)
652{
653	return ((struct libusb_control_setup *)transfer->buffer);
654}
655
656void
657libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
658    uint8_t bRequest, uint16_t wValue,
659    uint16_t wIndex, uint16_t wLength)
660{
661	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
662
663	/* The alignment is OK for all fields below. */
664	req->bmRequestType = bmRequestType;
665	req->bRequest = bRequest;
666	req->wValue = htole16(wValue);
667	req->wIndex = htole16(wIndex);
668	req->wLength = htole16(wLength);
669}
670
671void
672libusb_fill_control_transfer(struct libusb_transfer *transfer,
673    libusb_device_handle *devh, uint8_t *buf,
674    libusb_transfer_cb_fn callback, void *user_data,
675    uint32_t timeout)
676{
677	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
678
679	transfer->dev_handle = devh;
680	transfer->endpoint = 0;
681	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
682	transfer->timeout = timeout;
683	transfer->buffer = buf;
684	if (setup != NULL)
685		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
686			+ le16toh(setup->wLength);
687	else
688		transfer->length = 0;
689	transfer->user_data = user_data;
690	transfer->callback = callback;
691
692}
693
694void
695libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
696    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
697    int length, libusb_transfer_cb_fn callback, void *user_data,
698    uint32_t timeout)
699{
700	transfer->dev_handle = devh;
701	transfer->endpoint = endpoint;
702	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
703	transfer->timeout = timeout;
704	transfer->buffer = buf;
705	transfer->length = length;
706	transfer->user_data = user_data;
707	transfer->callback = callback;
708}
709
710void
711libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
712    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
713    int length, libusb_transfer_cb_fn callback, void *user_data,
714    uint32_t timeout)
715{
716	transfer->dev_handle = devh;
717	transfer->endpoint = endpoint;
718	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
719	transfer->timeout = timeout;
720	transfer->buffer = buf;
721	transfer->length = length;
722	transfer->user_data = user_data;
723	transfer->callback = callback;
724}
725
726void
727libusb_fill_iso_transfer(struct libusb_transfer *transfer,
728    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
729    int length, int npacket, libusb_transfer_cb_fn callback,
730    void *user_data, uint32_t timeout)
731{
732	transfer->dev_handle = devh;
733	transfer->endpoint = endpoint;
734	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
735	transfer->timeout = timeout;
736	transfer->buffer = buf;
737	transfer->length = length;
738	transfer->num_iso_packets = npacket;
739	transfer->user_data = user_data;
740	transfer->callback = callback;
741}
742
743