• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Isochronous IO functionality
3  *
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 
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/vmalloc.h>
25 #include <linux/mm.h>
26 
27 #include "fw-transaction.h"
28 #include "fw-topology.h"
29 #include "fw-device.h"
30 
31 int
fw_iso_buffer_init(struct fw_iso_buffer * buffer,struct fw_card * card,int page_count,enum dma_data_direction direction)32 fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
33 		   int page_count, enum dma_data_direction direction)
34 {
35 	int i, j, retval = -ENOMEM;
36 	dma_addr_t address;
37 
38 	buffer->page_count = page_count;
39 	buffer->direction = direction;
40 
41 	buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
42 				GFP_KERNEL);
43 	if (buffer->pages == NULL)
44 		goto out;
45 
46 	for (i = 0; i < buffer->page_count; i++) {
47 		buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
48 		if (buffer->pages[i] == NULL)
49 			goto out_pages;
50 
51 		address = dma_map_page(card->device, buffer->pages[i],
52 				       0, PAGE_SIZE, direction);
53 		if (dma_mapping_error(card->device, address)) {
54 			__free_page(buffer->pages[i]);
55 			goto out_pages;
56 		}
57 		set_page_private(buffer->pages[i], address);
58 	}
59 
60 	return 0;
61 
62  out_pages:
63 	for (j = 0; j < i; j++) {
64 		address = page_private(buffer->pages[j]);
65 		dma_unmap_page(card->device, address,
66 			       PAGE_SIZE, DMA_TO_DEVICE);
67 		__free_page(buffer->pages[j]);
68 	}
69 	kfree(buffer->pages);
70  out:
71 	buffer->pages = NULL;
72 	return retval;
73 }
74 
fw_iso_buffer_map(struct fw_iso_buffer * buffer,struct vm_area_struct * vma)75 int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
76 {
77 	unsigned long uaddr;
78 	int i, retval;
79 
80 	uaddr = vma->vm_start;
81 	for (i = 0; i < buffer->page_count; i++) {
82 		retval = vm_insert_page(vma, uaddr, buffer->pages[i]);
83 		if (retval)
84 			return retval;
85 		uaddr += PAGE_SIZE;
86 	}
87 
88 	return 0;
89 }
90 
fw_iso_buffer_destroy(struct fw_iso_buffer * buffer,struct fw_card * card)91 void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
92 			   struct fw_card *card)
93 {
94 	int i;
95 	dma_addr_t address;
96 
97 	for (i = 0; i < buffer->page_count; i++) {
98 		address = page_private(buffer->pages[i]);
99 		dma_unmap_page(card->device, address,
100 			       PAGE_SIZE, DMA_TO_DEVICE);
101 		__free_page(buffer->pages[i]);
102 	}
103 
104 	kfree(buffer->pages);
105 	buffer->pages = NULL;
106 }
107 
108 struct fw_iso_context *
fw_iso_context_create(struct fw_card * card,int type,int channel,int speed,size_t header_size,fw_iso_callback_t callback,void * callback_data)109 fw_iso_context_create(struct fw_card *card, int type,
110 		      int channel, int speed, size_t header_size,
111 		      fw_iso_callback_t callback, void *callback_data)
112 {
113 	struct fw_iso_context *ctx;
114 
115 	ctx = card->driver->allocate_iso_context(card, type, header_size);
116 	if (IS_ERR(ctx))
117 		return ctx;
118 
119 	ctx->card = card;
120 	ctx->type = type;
121 	ctx->channel = channel;
122 	ctx->speed = speed;
123 	ctx->header_size = header_size;
124 	ctx->callback = callback;
125 	ctx->callback_data = callback_data;
126 
127 	return ctx;
128 }
129 
fw_iso_context_destroy(struct fw_iso_context * ctx)130 void fw_iso_context_destroy(struct fw_iso_context *ctx)
131 {
132 	struct fw_card *card = ctx->card;
133 
134 	card->driver->free_iso_context(ctx);
135 }
136 
137 int
fw_iso_context_start(struct fw_iso_context * ctx,int cycle,int sync,int tags)138 fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags)
139 {
140 	return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
141 }
142 
143 int
fw_iso_context_queue(struct fw_iso_context * ctx,struct fw_iso_packet * packet,struct fw_iso_buffer * buffer,unsigned long payload)144 fw_iso_context_queue(struct fw_iso_context *ctx,
145 		     struct fw_iso_packet *packet,
146 		     struct fw_iso_buffer *buffer,
147 		     unsigned long payload)
148 {
149 	struct fw_card *card = ctx->card;
150 
151 	return card->driver->queue_iso(ctx, packet, buffer, payload);
152 }
153 
154 int
fw_iso_context_stop(struct fw_iso_context * ctx)155 fw_iso_context_stop(struct fw_iso_context *ctx)
156 {
157 	return ctx->card->driver->stop_iso(ctx);
158 }
159