fw-iso.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /* -*- c-basic-offset: 8 -*-
  2. *
  3. * fw-iso.c - Isochronous IO
  4. * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/dma-mapping.h>
  23. #include <linux/vmalloc.h>
  24. #include <linux/mm.h>
  25. #include "fw-transaction.h"
  26. #include "fw-topology.h"
  27. #include "fw-device.h"
  28. static int
  29. setup_iso_buffer(struct fw_iso_context *ctx, size_t size,
  30. enum dma_data_direction direction)
  31. {
  32. struct page *page;
  33. int i;
  34. void *p;
  35. ctx->buffer_size = PAGE_ALIGN(size);
  36. if (size == 0)
  37. return 0;
  38. ctx->buffer = vmalloc_32_user(ctx->buffer_size);
  39. if (ctx->buffer == NULL)
  40. return -ENOMEM;
  41. ctx->page_count = ctx->buffer_size >> PAGE_SHIFT;
  42. ctx->pages =
  43. kzalloc(ctx->page_count * sizeof(ctx->pages[0]), GFP_KERNEL);
  44. if (ctx->pages == NULL) {
  45. vfree(ctx->buffer);
  46. return -ENOMEM;
  47. }
  48. p = ctx->buffer;
  49. for (i = 0; i < ctx->page_count; i++, p += PAGE_SIZE) {
  50. page = vmalloc_to_page(p);
  51. ctx->pages[i] = dma_map_page(ctx->card->device,
  52. page, 0, PAGE_SIZE, direction);
  53. }
  54. return 0;
  55. }
  56. static void destroy_iso_buffer(struct fw_iso_context *ctx)
  57. {
  58. int i;
  59. for (i = 0; i < ctx->page_count; i++)
  60. dma_unmap_page(ctx->card->device, ctx->pages[i],
  61. PAGE_SIZE, DMA_TO_DEVICE);
  62. kfree(ctx->pages);
  63. vfree(ctx->buffer);
  64. }
  65. struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type,
  66. size_t buffer_size,
  67. fw_iso_callback_t callback,
  68. void *callback_data)
  69. {
  70. struct fw_iso_context *ctx;
  71. int retval;
  72. ctx = card->driver->allocate_iso_context(card, type);
  73. if (IS_ERR(ctx))
  74. return ctx;
  75. ctx->card = card;
  76. ctx->type = type;
  77. ctx->callback = callback;
  78. ctx->callback_data = callback_data;
  79. retval = setup_iso_buffer(ctx, buffer_size, DMA_TO_DEVICE);
  80. if (retval < 0) {
  81. card->driver->free_iso_context(ctx);
  82. return ERR_PTR(retval);
  83. }
  84. return ctx;
  85. }
  86. EXPORT_SYMBOL(fw_iso_context_create);
  87. void fw_iso_context_destroy(struct fw_iso_context *ctx)
  88. {
  89. struct fw_card *card = ctx->card;
  90. destroy_iso_buffer(ctx);
  91. card->driver->free_iso_context(ctx);
  92. }
  93. EXPORT_SYMBOL(fw_iso_context_destroy);
  94. int
  95. fw_iso_context_send(struct fw_iso_context *ctx,
  96. int channel, int speed, int cycle)
  97. {
  98. ctx->channel = channel;
  99. ctx->speed = speed;
  100. return ctx->card->driver->send_iso(ctx, cycle);
  101. }
  102. EXPORT_SYMBOL(fw_iso_context_send);
  103. int
  104. fw_iso_context_queue(struct fw_iso_context *ctx,
  105. struct fw_iso_packet *packet, void *payload)
  106. {
  107. struct fw_card *card = ctx->card;
  108. return card->driver->queue_iso(ctx, packet, payload);
  109. }
  110. EXPORT_SYMBOL(fw_iso_context_queue);