sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget` for a general overview of virtio.h](hThis document serves as a basic guideline for driver programmers that need to hack a new virtio driver or understand the essentials of the existing ones. See }(hhhhhNhNubh)}(h:ref:`Virtio on Linux `h]hinline)}(hhh]hVirtio on Linux}(hhhhhNhNubah}(h]h ](xrefstdstd-refeh"]h$]h&]uh1hhhubah}(h]h ]h"]h$]h&]refdoc(driver-api/virtio/writing_virtio_drivers refdomainjreftyperef refexplicitrefwarn reftargetvirtiouh1hhhhK hhubh" for a general overview of virtio.}(hhhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubeh}(h] introductionah ]h"] introductionah$]h&]uh1hhhhhhhhK ubh)}(hhh](h)}(hDriver boilerplateh]hDriver boilerplate}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj)hhhhhKubh)}(hX#As a bare minimum, a virtio driver needs to register in the virtio bus and configure the virtqueues for the device according to its spec, the configuration of the virtqueues in the driver side must match the virtqueue definitions in the device. A basic driver skeleton could look like this::h]hX"As a bare minimum, a virtio driver needs to register in the virtio bus and configure the virtqueues for the device according to its spec, the configuration of the virtqueues in the driver side must match the virtqueue definitions in the device. A basic driver skeleton could look like this:}(hj:hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj)hhubh literal_block)}(hX`#include #include #include #include /* device private data (one per device) */ struct virtio_dummy_dev { struct virtqueue *vq; }; static void virtio_dummy_recv_cb(struct virtqueue *vq) { struct virtio_dummy_dev *dev = vq->vdev->priv; char *buf; unsigned int len; while ((buf = virtqueue_get_buf(dev->vq, &len)) != NULL) { /* process the received data */ } } static int virtio_dummy_probe(struct virtio_device *vdev) { struct virtio_dummy_dev *dev = NULL; /* initialize device data */ dev = kzalloc(sizeof(struct virtio_dummy_dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* the device has a single virtqueue */ dev->vq = virtio_find_single_vq(vdev, virtio_dummy_recv_cb, "input"); if (IS_ERR(dev->vq)) { kfree(dev); return PTR_ERR(dev->vq); } vdev->priv = dev; /* from this point on, the device can notify and get callbacks */ virtio_device_ready(vdev); return 0; } static void virtio_dummy_remove(struct virtio_device *vdev) { struct virtio_dummy_dev *dev = vdev->priv; /* * disable vq interrupts: equivalent to * vdev->config->reset(vdev) */ virtio_reset_device(vdev); /* detach unused buffers */ while ((buf = virtqueue_detach_unused_buf(dev->vq)) != NULL) { kfree(buf); } /* remove virtqueues */ vdev->config->del_vqs(vdev); kfree(dev); } static const struct virtio_device_id id_table[] = { { VIRTIO_ID_DUMMY, VIRTIO_DEV_ANY_ID }, { 0 }, }; static struct virtio_driver virtio_dummy_driver = { .driver.name = KBUILD_MODNAME, .id_table = id_table, .probe = virtio_dummy_probe, .remove = virtio_dummy_remove, }; module_virtio_driver(virtio_dummy_driver); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Dummy virtio driver"); MODULE_LICENSE("GPL");h]hX`#include #include #include #include /* device private data (one per device) */ struct virtio_dummy_dev { struct virtqueue *vq; }; static void virtio_dummy_recv_cb(struct virtqueue *vq) { struct virtio_dummy_dev *dev = vq->vdev->priv; char *buf; unsigned int len; while ((buf = virtqueue_get_buf(dev->vq, &len)) != NULL) { /* process the received data */ } } static int virtio_dummy_probe(struct virtio_device *vdev) { struct virtio_dummy_dev *dev = NULL; /* initialize device data */ dev = kzalloc(sizeof(struct virtio_dummy_dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* the device has a single virtqueue */ dev->vq = virtio_find_single_vq(vdev, virtio_dummy_recv_cb, "input"); if (IS_ERR(dev->vq)) { kfree(dev); return PTR_ERR(dev->vq); } vdev->priv = dev; /* from this point on, the device can notify and get callbacks */ virtio_device_ready(vdev); return 0; } static void virtio_dummy_remove(struct virtio_device *vdev) { struct virtio_dummy_dev *dev = vdev->priv; /* * disable vq interrupts: equivalent to * vdev->config->reset(vdev) */ virtio_reset_device(vdev); /* detach unused buffers */ while ((buf = virtqueue_detach_unused_buf(dev->vq)) != NULL) { kfree(buf); } /* remove virtqueues */ vdev->config->del_vqs(vdev); kfree(dev); } static const struct virtio_device_id id_table[] = { { VIRTIO_ID_DUMMY, VIRTIO_DEV_ANY_ID }, { 0 }, }; static struct virtio_driver virtio_dummy_driver = { .driver.name = KBUILD_MODNAME, .id_table = id_table, .probe = virtio_dummy_probe, .remove = virtio_dummy_remove, }; module_virtio_driver(virtio_dummy_driver); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Dummy virtio driver"); MODULE_LICENSE("GPL");}hjJsbah}(h]h ]h"]h$]h&]hhuh1jHhhhKhj)hhubh)}(hXThe device id ``VIRTIO_ID_DUMMY`` here is a placeholder, virtio drivers should be added only for devices that are defined in the spec, see include/uapi/linux/virtio_ids.h. Device ids need to be at least reserved in the virtio spec before being added to that file.h](hThe device id }(hjXhhhNhNubhliteral)}(h``VIRTIO_ID_DUMMY``h]hVIRTIO_ID_DUMMY}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjXubh here is a placeholder, virtio drivers should be added only for devices that are defined in the spec, see include/uapi/linux/virtio_ids.h. Device ids need to be at least reserved in the virtio spec before being added to that file.}(hjXhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKnhj)hhubh)}(hIf your driver doesn't have to do anything special in its ``init`` and ``exit`` methods, you can use the module_virtio_driver() helper to reduce the amount of boilerplate code.h](hvq, sg, 1, buffer, GFP_ATOMIC); virtqueue_kick(dev->vq);h]hstruct scatterlist sg[1]; sg_init_one(sg, buffer, BUFLEN); virtqueue_add_inbuf(dev->vq, sg, 1, buffer, GFP_ATOMIC); virtqueue_kick(dev->vq);}hjZsbah}(h]h ]h"]h$]h&]hhuh1jHhhhKhjhhubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j virtqueue_add_inbuf (C function)c.virtqueue_add_inbufhNtauh1jhjhhhNhNubj)}(hhh](j)}(hoint virtqueue_add_inbuf (struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h]j)}(hnint virtqueue_add_inbuf(struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h](j)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj}hhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMK ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj}hhhjhMK ubj$)}(hvirtqueue_add_inbufh]j*)}(hvirtqueue_add_inbufh]hvirtqueue_add_inbuf}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hj}hhhjhMK ubjC)}(hW(struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h](jI)}(hstruct virtqueue *vqh](jO)}(hjRh]hstruct}(hjhhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j)}jjsbc.virtqueue_add_inbufasbuh1hhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hvqh]hvq}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(hstruct scatterlist *sgh](jO)}(hjRh]hstruct}(hj0hhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhj,ubj)}(h h]h }(hj=hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj,ubh)}(hhh]j*)}(h scatterlisth]h scatterlist}(hjNhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjKubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjPmodnameN classnameNjj)}j]jc.virtqueue_add_inbufasbuh1hhj,ubj)}(h h]h }(hjlhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj,ubj)}(hjh]h*}(hjzhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj,ubj*)}(hsgh]hsg}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj,ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(hunsigned int numh](j)}(hunsignedh]hunsigned}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hnumh]hnum}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(h void *datah](j)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hdatah]hdata}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(h gfp_t gfph](h)}(hhh]j*)}(hgfp_th]hgfp_t}(hj6hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj3ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj8modnameN classnameNjj)}j]jc.virtqueue_add_inbufasbuh1hhj/ubj)}(h h]h }(hjThhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj/ubj*)}(hgfph]hgfp}(hjbhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj/ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubeh}(h]h ]h"]h$]h&]hhuh1jBhj}hhhjhMK ubeh}(h]h ]h"]h$]h&]hhjuh1jjjhjyhhhjhMK ubah}(h]jtah ](jjeh"]h$]h&]jj)jhuh1jhjhMK hjvhhubj)}(hhh]h)}(h!expose input buffers to other endh]h!expose input buffers to other end}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chM? hjhhubah}(h]h ]h"]h$]h&]uh1jhjvhhhjhMK ubeh}(h]h ](jfunctioneh"]h$]h&]jjj jj jj j j uh1jhhhjhNhNubj)}(hX!**Parameters** ``struct virtqueue *vq`` the struct virtqueue we're talking about. ``struct scatterlist *sg`` scatterlist (must be well-formed and terminated!) ``unsigned int num`` the number of entries in **sg** writable by other side ``void *data`` the token identifying the buffer. ``gfp_t gfp`` how to do memory allocations (if necessary). **Description** Caller must ensure we don't call this with other virtqueue operations at the same time (except where noted). Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h](h)}(h**Parameters**h]j)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMC hjubj/)}(hhh](j4)}(hC``struct virtqueue *vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *vq``h]ja)}(hjh]hstruct virtqueue *vq}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chM@ hjubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM@ hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhM@ hjubj4)}(hM``struct scatterlist *sg`` scatterlist (must be well-formed and terminated!) h](j:)}(h``struct scatterlist *sg``h]ja)}(hjh]hstruct scatterlist *sg}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMA hjubjT)}(hhh]h)}(h1scatterlist (must be well-formed and terminated!)h]h1scatterlist (must be well-formed and terminated!)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMA hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMA hjubj4)}(hL``unsigned int num`` the number of entries in **sg** writable by other side h](j:)}(h``unsigned int num``h]ja)}(hj?h]hunsigned int num}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hj=ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMB hj9ubjT)}(hhh]h)}(h6the number of entries in **sg** writable by other sideh](hthe number of entries in }(hjXhhhNhNubj)}(h**sg**h]hsg}(hj`hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjXubh writable by other side}(hjXhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjThMB hjUubah}(h]h ]h"]h$]h&]uh1jShj9ubeh}(h]h ]h"]h$]h&]uh1j3hjThMB hjubj4)}(h1``void *data`` the token identifying the buffer. h](j:)}(h``void *data``h]ja)}(hjh]h void *data}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMC hjubjT)}(hhh]h)}(h!the token identifying the buffer.h]h!the token identifying the buffer.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMC hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMC hjubj4)}(h;``gfp_t gfp`` how to do memory allocations (if necessary). h](j:)}(h ``gfp_t gfp``h]ja)}(hjh]h gfp_t gfp}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMD hjubjT)}(hhh]h)}(h,how to do memory allocations (if necessary).h]h,how to do memory allocations (if necessary).}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMD hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMD hjubeh}(h]h ]h"]h$]h&]uh1j.hjubh)}(h**Description**h]j)}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMF hjubh)}(hlCaller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h]hnCaller must ensure we don’t call this with other virtqueue operations at the same time (except where noted).}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMF hjubh)}(h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h]h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:157: ./drivers/virtio/virtio_ring.chMI hjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j!virtqueue_add_outbuf (C function)c.virtqueue_add_outbufhNtauh1jhjhhhNhNubj)}(hhh](j)}(hpint virtqueue_add_outbuf (struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h]j)}(hoint virtqueue_add_outbuf(struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h](j)}(hinth]hint}(hjRhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjNhhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM ubj)}(h h]h }(hjahhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjNhhhj`hM ubj$)}(hvirtqueue_add_outbufh]j*)}(hvirtqueue_add_outbufh]hvirtqueue_add_outbuf}(hjshhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjoubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hjNhhhj`hM ubjC)}(hW(struct virtqueue *vq, struct scatterlist *sg, unsigned int num, void *data, gfp_t gfp)h](jI)}(hstruct virtqueue *vqh](jO)}(hjRh]hstruct}(hjhhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j)}jjusbc.virtqueue_add_outbufasbuh1hhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hvqh]hvq}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(hstruct scatterlist *sgh](jO)}(hjRh]hstruct}(hj hhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j*)}(h scatterlisth]h scatterlist}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj! modnameN classnameNjj)}j]jc.virtqueue_add_outbufasbuh1hhjubj)}(h h]h }(hj= hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hjK hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hsgh]hsg}(hjX hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(hunsigned int numh](j)}(hunsignedh]hunsigned}(hjq hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjm ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjm ubj)}(hinth]hint}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjm ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjm ubj*)}(hnumh]hnum}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjm ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(h void *datah](j)}(hvoidh]hvoid}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj*)}(hdatah]hdata}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(h gfp_t gfph](h)}(hhh]j*)}(hgfp_th]hgfp_t}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]jc.virtqueue_add_outbufasbuh1hhj ubj)}(h h]h }(hj% hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj*)}(hgfph]hgfp}(hj3 hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubeh}(h]h ]h"]h$]h&]hhuh1jBhjNhhhj`hM ubeh}(h]h ]h"]h$]h&]hhjuh1jjjhjJhhhj`hM ubah}(h]jEah ](jjeh"]h$]h&]jj)jhuh1jhj`hM hjGhhubj)}(hhh]h)}(h"expose output buffers to other endh]h"expose output buffers to other end}(hj] hhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjZ hhubah}(h]h ]h"]h$]h&]uh1jhjGhhhj`hM ubeh}(h]h ](jfunctioneh"]h$]h&]jjj ju j ju j j j uh1jhhhjhNhNubj)}(hX!**Parameters** ``struct virtqueue *vq`` the struct virtqueue we're talking about. ``struct scatterlist *sg`` scatterlist (must be well-formed and terminated!) ``unsigned int num`` the number of entries in **sg** readable by other side ``void *data`` the token identifying the buffer. ``gfp_t gfp`` how to do memory allocations (if necessary). **Description** Caller must ensure we don't call this with other virtqueue operations at the same time (except where noted). Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h](h)}(h**Parameters**h]j)}(hj h]h Parameters}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj} ubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjy ubj/)}(hhh](j4)}(hC``struct virtqueue *vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *vq``h]ja)}(hj h]hstruct virtqueue *vq}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j`hj ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hj ubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hM hj ubah}(h]h ]h"]h$]h&]uh1jShj ubeh}(h]h ]h"]h$]h&]uh1j3hj hM hj ubj4)}(hM``struct scatterlist *sg`` scatterlist (must be well-formed and terminated!) h](j:)}(h``struct scatterlist *sg``h]ja)}(hj h]hstruct scatterlist *sg}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j`hj ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hj ubjT)}(hhh]h)}(h1scatterlist (must be well-formed and terminated!)h]h1scatterlist (must be well-formed and terminated!)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hM hj ubah}(h]h ]h"]h$]h&]uh1jShj ubeh}(h]h ]h"]h$]h&]uh1j3hj hM hj ubj4)}(hL``unsigned int num`` the number of entries in **sg** readable by other side h](j:)}(h``unsigned int num``h]ja)}(hj h]hunsigned int num}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j`hj ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hj ubjT)}(hhh]h)}(h6the number of entries in **sg** readable by other sideh](hthe number of entries in }(hj) hhhNhNubj)}(h**sg**h]hsg}(hj1 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj) ubh readable by other side}(hj) hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj% hM hj& ubah}(h]h ]h"]h$]h&]uh1jShj ubeh}(h]h ]h"]h$]h&]uh1j3hj% hM hj ubj4)}(h1``void *data`` the token identifying the buffer. h](j:)}(h``void *data``h]ja)}(hj[ h]h void *data}(hj] hhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjY ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjU ubjT)}(hhh]h)}(h!the token identifying the buffer.h]h!the token identifying the buffer.}(hjt hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjp hM hjq ubah}(h]h ]h"]h$]h&]uh1jShjU ubeh}(h]h ]h"]h$]h&]uh1j3hjp hM hj ubj4)}(h;``gfp_t gfp`` how to do memory allocations (if necessary). h](j:)}(h ``gfp_t gfp``h]ja)}(hj h]h gfp_t gfp}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j`hj ubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hj ubjT)}(hhh]h)}(h,how to do memory allocations (if necessary).h]h,how to do memory allocations (if necessary).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hM hj ubah}(h]h ]h"]h$]h&]uh1jShj ubeh}(h]h ]h"]h$]h&]uh1j3hj hM hj ubeh}(h]h ]h"]h$]h&]uh1j.hjy ubh)}(h**Description**h]j)}(hj h]h Description}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjy ubh)}(hlCaller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h]hnCaller must ensure we don’t call this with other virtqueue operations at the same time (except where noted).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjy ubh)}(h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h]h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:160: ./drivers/virtio/virtio_ring.chM hjy ubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](jvirtqueue_add_sgs (C function)c.virtqueue_add_sgshNtauh1jhjhhhNhNubj)}(hhh](j)}(hint virtqueue_add_sgs (struct virtqueue *_vq, struct scatterlist *sgs[], unsigned int out_sgs, unsigned int in_sgs, void *data, gfp_t gfp)h]j)}(hint virtqueue_add_sgs(struct virtqueue *_vq, struct scatterlist *sgs[], unsigned int out_sgs, unsigned int in_sgs, void *data, gfp_t gfp)h](j)}(hinth]hint}(hj# hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj hhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMubj)}(h h]h }(hj2 hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj hhhj1 hMubj$)}(hvirtqueue_add_sgsh]j*)}(hvirtqueue_add_sgsh]hvirtqueue_add_sgs}(hjD hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj@ ubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hj hhhj1 hMubjC)}(ht(struct virtqueue *_vq, struct scatterlist *sgs[], unsigned int out_sgs, unsigned int in_sgs, void *data, gfp_t gfp)h](jI)}(hstruct virtqueue *_vqh](jO)}(hjRh]hstruct}(hj` hhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhj\ ubj)}(h h]h }(hjm hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj\ ubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hj~ hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj{ ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]j)}jjF sbc.virtqueue_add_sgsasbuh1hhj\ ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj\ ubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj\ ubj*)}(h_vqh]h_vq}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj\ ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubjI)}(hstruct scatterlist *sgs[]h](jO)}(hjRh]hstruct}(hj hhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubh)}(hhh]j*)}(h scatterlisth]h scatterlist}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]j c.virtqueue_add_sgsasbuh1hhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj*)}(hsgsh]hsgs}(hj) hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubj)}(h[h]h[}(hj7 hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(h]h]h]}(hjE hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubjI)}(hunsigned int out_sgsh](j)}(hunsignedh]hunsigned}(hj^ hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjZ ubj)}(h h]h }(hjl hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjZ ubj)}(hinth]hint}(hjz hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjZ ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjZ ubj*)}(hout_sgsh]hout_sgs}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjZ ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubjI)}(hunsigned int in_sgsh](j)}(hunsignedh]hunsigned}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(hinth]hint}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj*)}(hin_sgsh]hin_sgs}(hj hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubjI)}(h void *datah](j)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj*)}(hdatah]hdata}(hj)hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubjI)}(h gfp_t gfph](h)}(hhh]j*)}(hgfp_th]hgfp_t}(hjEhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjBubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjGmodnameN classnameNjj)}j]j c.virtqueue_add_sgsasbuh1hhj>ubj)}(h h]h }(hjchhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj>ubj*)}(hgfph]hgfp}(hjqhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj>ubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjX ubeh}(h]h ]h"]h$]h&]hhuh1jBhj hhhj1 hMubeh}(h]h ]h"]h$]h&]hhjuh1jjjhj hhhj1 hMubah}(h]j ah ](jjeh"]h$]h&]jj)jhuh1jhj1 hMhj hhubj)}(hhh]h)}(hexpose buffers to other endh]hexpose buffers to other end}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjhhubah}(h]h ]h"]h$]h&]uh1jhj hhhj1 hMubeh}(h]h ](jfunctioneh"]h$]h&]jjj jj jj j j uh1jhhhjhNhNubj)}(hXs**Parameters** ``struct virtqueue *_vq`` the struct virtqueue we're talking about. ``struct scatterlist *sgs[]`` array of terminated scatterlists. ``unsigned int out_sgs`` the number of scatterlists readable by other side ``unsigned int in_sgs`` the number of scatterlists which are writable (after readable ones) ``void *data`` the token identifying the buffer. ``gfp_t gfp`` how to do memory allocations (if necessary). **Description** Caller must ensure we don't call this with other virtqueue operations at the same time (except where noted). Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h](h)}(h**Parameters**h]j)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubj/)}(hhh](j4)}(hD``struct virtqueue *_vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *_vq``h]ja)}(hjh]hstruct virtqueue *_vq}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMhjubj4)}(h@``struct scatterlist *sgs[]`` array of terminated scatterlists. h](j:)}(h``struct scatterlist *sgs[]``h]ja)}(hjh]hstruct scatterlist *sgs[]}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubjT)}(hhh]h)}(h!array of terminated scatterlists.h]h!array of terminated scatterlists.}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj*hMhj+ubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hj*hMhjubj4)}(hK``unsigned int out_sgs`` the number of scatterlists readable by other side h](j:)}(h``unsigned int out_sgs``h]ja)}(hjNh]hunsigned int out_sgs}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjLubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjHubjT)}(hhh]h)}(h1the number of scatterlists readable by other sideh]h1the number of scatterlists readable by other side}(hjghhhNhNubah}(h]h ]h"]h$]h&]uh1hhjchMhjdubah}(h]h ]h"]h$]h&]uh1jShjHubeh}(h]h ]h"]h$]h&]uh1j3hjchMhjubj4)}(h\``unsigned int in_sgs`` the number of scatterlists which are writable (after readable ones) h](j:)}(h``unsigned int in_sgs``h]ja)}(hjh]hunsigned int in_sgs}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubjT)}(hhh]h)}(hCthe number of scatterlists which are writable (after readable ones)h]hCthe number of scatterlists which are writable (after readable ones)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMhjubj4)}(h1``void *data`` the token identifying the buffer. h](j:)}(h``void *data``h]ja)}(hjh]h void *data}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubjT)}(hhh]h)}(h!the token identifying the buffer.h]h!the token identifying the buffer.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMhjubj4)}(h;``gfp_t gfp`` how to do memory allocations (if necessary). h](j:)}(h ``gfp_t gfp``h]ja)}(hjh]h gfp_t gfp}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubjT)}(hhh]h)}(h,how to do memory allocations (if necessary).h]h,how to do memory allocations (if necessary).}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhMhjubeh}(h]h ]h"]h$]h&]uh1j.hjubh)}(h**Description**h]j)}(hj4h]h Description}(hj6hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj2ubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubh)}(hlCaller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h]hnCaller must ensure we don’t call this with other virtqueue operations at the same time (except where noted).}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubh)}(h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).h]h;Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:163: ./drivers/virtio/virtio_ring.chMhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubh)}(hX2Then, after the device has read or written the buffers prepared by the driver and notifies it back, the driver can call virtqueue_get_buf() to read the data produced by the device (if the virtqueue was set up with input buffers) or simply to reclaim the buffers if they were already consumed by the device:h]hX2Then, after the device has read or written the buffers prepared by the driver and notifies it back, the driver can call virtqueue_get_buf() to read the data produced by the device (if the virtqueue was set up with input buffers) or simply to reclaim the buffers if they were already consumed by the device:}(hjohhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j"virtqueue_get_buf_ctx (C function)c.virtqueue_get_buf_ctxhNtauh1jhjhhhNhNubj)}(hhh](j)}(hSvoid * virtqueue_get_buf_ctx (struct virtqueue *_vq, unsigned int *len, void **ctx)h]j)}(hQvoid *virtqueue_get_buf_ctx(struct virtqueue *_vq, unsigned int *len, void **ctx)h](j)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjhhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjhhhjhM ubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjhhhjhM ubj$)}(hvirtqueue_get_buf_ctxh]j*)}(hvirtqueue_get_buf_ctxh]hvirtqueue_get_buf_ctx}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hjhhhjhM ubjC)}(h6(struct virtqueue *_vq, unsigned int *len, void **ctx)h](jI)}(hstruct virtqueue *_vqh](jO)}(hjRh]hstruct}(hjhhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j)}jjsbc.virtqueue_get_buf_ctxasbuh1hhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hj,hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(h_vqh]h_vq}(hj9hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(hunsigned int *lenh](j)}(hunsignedh]hunsigned}(hjRhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjNubj)}(h h]h }(hj`hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjNubj)}(hinth]hint}(hjnhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjNubj)}(h h]h }(hj|hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjNubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjNubj*)}(hlenh]hlen}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjNubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubjI)}(h void **ctxh](j)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(hctxh]hctx}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubeh}(h]h ]h"]h$]h&]hhuh1jBhjhhhjhM ubeh}(h]h ]h"]h$]h&]hhjuh1jjjhjhhhjhM ubah}(h]jah ](jjeh"]h$]h&]jj)jhuh1jhjhM hjhhubj)}(hhh]h)}(hget the next used bufferh]hget the next used buffer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj hhubah}(h]h ]h"]h$]h&]uh1jhjhhhjhM ubeh}(h]h ](jfunctioneh"]h$]h&]jjj j(j j(j j j uh1jhhhjhNhNubj)}(hXj**Parameters** ``struct virtqueue *_vq`` the struct virtqueue we're talking about. ``unsigned int *len`` the length written into the buffer ``void **ctx`` extra context for the token **Description** If the device wrote data into the buffer, **len** will be set to the amount written. This means you don't need to clear the buffer beforehand to ensure there's no data leakage in the case of short writes. Caller must ensure we don't call this with other virtqueue operations at the same time (except where noted). Returns NULL if there are no used buffers, or the "data" token handed to virtqueue_add_*().h](h)}(h**Parameters**h]j)}(hj2h]h Parameters}(hj4hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj0ubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj,ubj/)}(hhh](j4)}(hD``struct virtqueue *_vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *_vq``h]ja)}(hjQh]hstruct virtqueue *_vq}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjOubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hjKubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjfhM hjgubah}(h]h ]h"]h$]h&]uh1jShjKubeh}(h]h ]h"]h$]h&]uh1j3hjfhM hjHubj4)}(h9``unsigned int *len`` the length written into the buffer h](j:)}(h``unsigned int *len``h]ja)}(hjh]hunsigned int *len}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hjubjT)}(hhh]h)}(h"the length written into the bufferh]h"the length written into the buffer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhM hjHubj4)}(h+``void **ctx`` extra context for the token h](j:)}(h``void **ctx``h]ja)}(hjh]h void **ctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hjubjT)}(hhh]h)}(hextra context for the tokenh]hextra context for the token}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM hjubah}(h]h ]h"]h$]h&]uh1jShjubeh}(h]h ]h"]h$]h&]uh1j3hjhM hjHubeh}(h]h ]h"]h$]h&]uh1j.hj,ubh)}(h**Description**h]j)}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj,ubh)}(hIf the device wrote data into the buffer, **len** will be set to the amount written. This means you don't need to clear the buffer beforehand to ensure there's no data leakage in the case of short writes.h](h*If the device wrote data into the buffer, }(hjhhhNhNubj)}(h**len**h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh will be set to the amount written. This means you don’t need to clear the buffer beforehand to ensure there’s no data leakage in the case of short writes.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj,ubh)}(hlCaller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h]hnCaller must ensure we don’t call this with other virtqueue operations at the same time (except where noted).}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj,ubh)}(h[Returns NULL if there are no used buffers, or the "data" token handed to virtqueue_add_*().h]h_Returns NULL if there are no used buffers, or the “data” token handed to virtqueue_add_*().}(hjDhhhNh=Nubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:172: ./drivers/virtio/virtio_ring.chM hj,ubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubh)}(hThe virtqueue callbacks can be disabled and re-enabled using the virtqueue_disable_cb() and the family of virtqueue_enable_cb() functions respectively. See drivers/virtio/virtio_ring.c for more details:h]hThe virtqueue callbacks can be disabled and re-enabled using the virtqueue_disable_cb() and the family of virtqueue_enable_cb() functions respectively. See drivers/virtio/virtio_ring.c for more details:}(hjZhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j!virtqueue_disable_cb (C function)c.virtqueue_disable_cbhNtauh1jhjhhhNhNubj)}(hhh](j)}(h1void virtqueue_disable_cb (struct virtqueue *_vq)h]j)}(h0void virtqueue_disable_cb(struct virtqueue *_vq)h](j)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj}hhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj}hhhjhM ubj$)}(hvirtqueue_disable_cbh]j*)}(hvirtqueue_disable_cbh]hvirtqueue_disable_cb}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hj}hhhjhM ubjC)}(h(struct virtqueue *_vq)h]jI)}(hstruct virtqueue *_vqh](jO)}(hjRh]hstruct}(hjhhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j)}jjsbc.virtqueue_disable_cbasbuh1hhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj*)}(h_vqh]h_vq}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjubah}(h]h ]h"]h$]h&]hhuh1jBhj}hhhjhM ubeh}(h]h ]h"]h$]h&]hhjuh1jjjhjyhhhjhM ubah}(h]jtah ](jjeh"]h$]h&]jj)jhuh1jhjhM hjvhhubj)}(hhh]h)}(hdisable callbacksh]hdisable callbacks}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj>hhubah}(h]h ]h"]h$]h&]uh1jhjvhhhjhM ubeh}(h]h ](jfunctioneh"]h$]h&]jjj jYj jYj j j uh1jhhhjhNhNubj)}(hX**Parameters** ``struct virtqueue *_vq`` the struct virtqueue we're talking about. **Description** Note that this is not necessarily synchronous, hence unreliable and only useful as an optimization. Unlike other operations, this need not be serialized.h](h)}(h**Parameters**h]j)}(hjch]h Parameters}(hjehhhNhNubah}(h]h ]h"]h$]h&]uh1jhjaubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj]ubj/)}(hhh]j4)}(hD``struct virtqueue *_vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *_vq``h]ja)}(hjh]hstruct virtqueue *_vq}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj|ubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM hjubah}(h]h ]h"]h$]h&]uh1jShj|ubeh}(h]h ]h"]h$]h&]uh1j3hjhM hjyubah}(h]h ]h"]h$]h&]uh1j.hj]ubh)}(h**Description**h]j)}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj]ubh)}(hcNote that this is not necessarily synchronous, hence unreliable and only useful as an optimization.h]hcNote that this is not necessarily synchronous, hence unreliable and only useful as an optimization.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj]ubh)}(h5Unlike other operations, this need not be serialized.h]h5Unlike other operations, this need not be serialized.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:179: ./drivers/virtio/virtio_ring.chM hj]ubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j virtqueue_enable_cb (C function)c.virtqueue_enable_cbhNtauh1jhjhhhNhNubj)}(hhh](j)}(h0bool virtqueue_enable_cb (struct virtqueue *_vq)h]j)}(h/bool virtqueue_enable_cb(struct virtqueue *_vq)h](j)}(hboolh]hbool}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj hhhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chMC ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj hhhjhMC ubj$)}(hvirtqueue_enable_cbh]j*)}(hvirtqueue_enable_cbh]hvirtqueue_enable_cb}(hj2hhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hj.ubah}(h]h ](j=j>eh"]h$]h&]hhuh1j#hj hhhjhMC ubjC)}(h(struct virtqueue *_vq)h]jI)}(hstruct virtqueue *_vqh](jO)}(hjRh]hstruct}(hjNhhhNhNubah}(h]h ]j[ah"]h$]h&]uh1jNhjJubj)}(h h]h }(hj[hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjJubh)}(hhh]j*)}(h virtqueueh]h virtqueue}(hjlhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjiubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjnmodnameN classnameNjj)}j]j)}jj4sbc.virtqueue_enable_cbasbuh1hhjJubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjJubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjJubj*)}(h_vqh]h_vq}(hjhhhNhNubah}(h]h ]j6ah"]h$]h&]uh1j)hjJubeh}(h]h ]h"]h$]h&]noemphhhuh1jHhjFubah}(h]h ]h"]h$]h&]hhuh1jBhj hhhjhMC ubeh}(h]h ]h"]h$]h&]hhjuh1jjjhj hhhjhMC ubah}(h]jah ](jjeh"]h$]h&]jj)jhuh1jhjhMC hjhhubj)}(hhh]h)}(h#restart callbacks after disable_cb.h]h#restart callbacks after disable_cb.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM9 hjhhubah}(h]h ]h"]h$]h&]uh1jhjhhhjhMC ubeh}(h]h ](jfunctioneh"]h$]h&]jjj jj jj j j uh1jhhhjhNhNubj)}(hX**Parameters** ``struct virtqueue *_vq`` the struct virtqueue we're talking about. **Description** This re-enables callbacks; it returns "false" if there are pending buffers in the queue, to detect a possible race between the driver checking for more work, and enabling callbacks. Caller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h](h)}(h**Parameters**h]j)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM= hjubj/)}(hhh]j4)}(hD``struct virtqueue *_vq`` the struct virtqueue we're talking about. h](j:)}(h``struct virtqueue *_vq``h]ja)}(hjh]hstruct virtqueue *_vq}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j`hjubah}(h]h ]h"]h$]h&]uh1j9hv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM: hj ubjT)}(hhh]h)}(h)the struct virtqueue we're talking about.h]h+the struct virtqueue we’re talking about.}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj'hM: hj(ubah}(h]h ]h"]h$]h&]uh1jShj ubeh}(h]h ]h"]h$]h&]uh1j3hj'hM: hj ubah}(h]h ]h"]h$]h&]uh1j.hjubh)}(h**Description**h]j)}(hjMh]h Description}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjKubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM< hjubh)}(hThis re-enables callbacks; it returns "false" if there are pending buffers in the queue, to detect a possible race between the driver checking for more work, and enabling callbacks.h]hThis re-enables callbacks; it returns “false” if there are pending buffers in the queue, to detect a possible race between the driver checking for more work, and enabling callbacks.}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM< hjubh)}(hlCaller must ensure we don't call this with other virtqueue operations at the same time (except where noted).h]hnCaller must ensure we don’t call this with other virtqueue operations at the same time (except where noted).}(hjrhhhNhNubah}(h]h ]h"]h$]h&]uh1hhv/var/lib/git/docbuild/linux/Documentation/driver-api/virtio/writing_virtio_drivers:182: ./drivers/virtio/virtio_ring.chM@ hjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjhhhNhNubh)}(hBut note that some spurious callbacks can still be triggered under certain scenarios. The way to disable callbacks reliably is to reset the device or the virtqueue (virtio_reset_device()).h]hBut note that some spurious callbacks can still be triggered under certain scenarios. The way to disable callbacks reliably is to reset the device or the virtqueue (virtio_reset_device()).}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]sending-and-receiving-dataah ]h"]sending and receiving dataah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h Referencesh]h References}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hX_`[1]` Virtio Spec v1.2: https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.htmlh](h)}(h_`[1]`h]h[1]}(hjhhhNhNubah}(h]id2ah ]h"][1]ah$]h&]uh1hhjubh Virtio Spec v1.2: }(hjhhhNhNubh reference)}(h?https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.htmlh]h?https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurijuh1jhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(h-Check for later versions of the spec as well.h]h-Check for later versions of the spec as well.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h] referencesah ]h"] referencesah$]h&]uh1hhhhhhhhKubeh}(h](hid1eh ]h"](writing virtio driverswriting_virtio_driverseh$]h&]uh1hhhhhhhhKexpect_referenced_by_name}jhsexpect_referenced_by_id}hhsubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj$error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}h]hasnameids}(jhjjj&j#jjjjjjjju nametypes}(jjj&jjjjuh}(hhjhj#hjj)jjjjjtjyjEjJj j jjjtjyjj jjjju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j2KsRparse_messages]transform_messages](hsystem_message)}(hhh]h)}(hhh]h