firedtv-1394.c 6.6 KB
Newer Older
G
Greg Kroah-Hartman 已提交
1
/*
2
 * FireDTV driver (formerly known as FireSAT)
G
Greg Kroah-Hartman 已提交
3
 *
4 5 6
 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
 * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
G
Greg Kroah-Hartman 已提交
7 8 9 10 11 12 13
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License as
 *	published by the Free Software Foundation; either version 2 of
 *	the License, or (at your option) any later version.
 */

14
#include <linux/device.h>
G
Greg Kroah-Hartman 已提交
15
#include <linux/errno.h>
16 17 18 19 20
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/types.h>

S
Stefan Richter 已提交
21
#include <dma.h>
22
#include <csr1212.h>
G
Greg Kroah-Hartman 已提交
23 24
#include <highlevel.h>
#include <hosts.h>
S
Stefan Richter 已提交
25 26
#include <ieee1394.h>
#include <iso.h>
27
#include <nodemgr.h>
G
Greg Kroah-Hartman 已提交
28

29
#include "firedtv.h"
G
Greg Kroah-Hartman 已提交
30

S
Stefan Richter 已提交
31 32
static LIST_HEAD(node_list);
static DEFINE_SPINLOCK(node_list_lock);
G
Greg Kroah-Hartman 已提交
33

S
Stefan Richter 已提交
34 35
#define FIREWIRE_HEADER_SIZE	4
#define CIP_HEADER_SIZE		8
G
Greg Kroah-Hartman 已提交
36

S
Stefan Richter 已提交
37
static void rawiso_activity_cb(struct hpsb_iso *iso)
G
Greg Kroah-Hartman 已提交
38
{
S
Stefan Richter 已提交
39 40 41
	struct firedtv *f, *fdtv = NULL;
	unsigned int i, num, packet;
	unsigned char *buf;
G
Greg Kroah-Hartman 已提交
42
	unsigned long flags;
S
Stefan Richter 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	int count;

	spin_lock_irqsave(&node_list_lock, flags);
	list_for_each_entry(f, &node_list, list)
		if (f->backend_data == iso) {
			fdtv = f;
			break;
		}
	spin_unlock_irqrestore(&node_list_lock, flags);

	packet = iso->first_packet;
	num = hpsb_iso_n_ready(iso);

	if (!fdtv) {
		dev_err(fdtv->device, "received at unknown iso channel\n");
		goto out;
	}
G
Greg Kroah-Hartman 已提交
60

S
Stefan Richter 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) {
		buf = dma_region_i(&iso->data_buf, unsigned char,
			iso->infos[packet].offset + CIP_HEADER_SIZE);
		count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
			(188 + FIREWIRE_HEADER_SIZE);

		/* ignore empty packet */
		if (iso->infos[packet].len <= CIP_HEADER_SIZE)
			continue;

		while (count--) {
			if (buf[FIREWIRE_HEADER_SIZE] == 0x47)
				dvb_dmx_swfilter_packets(&fdtv->demux,
						&buf[FIREWIRE_HEADER_SIZE], 1);
			else
				dev_err(fdtv->device,
					"skipping invalid packet\n");
			buf += 188 + FIREWIRE_HEADER_SIZE;
G
Greg Kroah-Hartman 已提交
79
		}
S
Stefan Richter 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	}
out:
	hpsb_iso_recv_release_packets(iso, num);
}

static inline struct node_entry *node_of(struct firedtv *fdtv)
{
	return container_of(fdtv->device, struct unit_directory, device)->ne;
}

static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg)
{
	return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data,
			      (__force quadlet_t)arg);
}

static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
{
	return hpsb_node_read(node_of(fdtv), addr, data, len);
}

static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
{
	return hpsb_node_write(node_of(fdtv), addr, data, len);
}

#define FDTV_ISO_BUFFER_PACKETS 256
#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200)

static int start_iso(struct firedtv *fdtv)
{
	struct hpsb_iso *iso_handle;
	int ret;

	iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host,
				FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS,
				fdtv->isochannel, HPSB_ISO_DMA_DEFAULT,
				-1, /* stat.config.irq_interval */
				rawiso_activity_cb);
	if (iso_handle == NULL) {
		dev_err(fdtv->device, "cannot initialize iso receive\n");
		return -ENOMEM;
	}
	fdtv->backend_data = iso_handle;

	ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0);
	if (ret != 0) {
		dev_err(fdtv->device, "cannot start iso receive\n");
		hpsb_iso_shutdown(iso_handle);
		fdtv->backend_data = NULL;
	}
	return ret;
}

static void stop_iso(struct firedtv *fdtv)
{
	struct hpsb_iso *iso_handle = fdtv->backend_data;
G
Greg Kroah-Hartman 已提交
137

S
Stefan Richter 已提交
138 139 140
	if (iso_handle != NULL) {
		hpsb_iso_stop(iso_handle);
		hpsb_iso_shutdown(iso_handle);
141
	}
S
Stefan Richter 已提交
142
	fdtv->backend_data = NULL;
G
Greg Kroah-Hartman 已提交
143 144
}

S
Stefan Richter 已提交
145 146 147 148 149 150
static const struct firedtv_backend fdtv_1394_backend = {
	.lock		= node_lock,
	.read		= node_read,
	.write		= node_write,
	.start_iso	= start_iso,
	.stop_iso	= stop_iso,
151 152
};

S
Stefan Richter 已提交
153 154
static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
			int cts, u8 *data, size_t length)
G
Greg Kroah-Hartman 已提交
155
{
S
Stefan Richter 已提交
156
	struct firedtv *f, *fdtv = NULL;
G
Greg Kroah-Hartman 已提交
157
	unsigned long flags;
S
Stefan Richter 已提交
158
	int su;
G
Greg Kroah-Hartman 已提交
159

S
Stefan Richter 已提交
160 161
	if (length == 0 || (data[0] & 0xf0) != 0)
		return;
162

S
Stefan Richter 已提交
163 164 165 166 167 168 169 170 171 172 173
	su = data[1] & 0x7;

	spin_lock_irqsave(&node_list_lock, flags);
	list_for_each_entry(f, &node_list, list)
		if (node_of(f)->host == host &&
		    node_of(f)->nodeid == nodeid &&
		    (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
			fdtv = f;
			break;
		}
	spin_unlock_irqrestore(&node_list_lock, flags);
174

S
Stefan Richter 已提交
175 176 177 178 179 180 181 182 183 184 185
	if (fdtv)
		avc_recv(fdtv, data, length);
}

static int node_probe(struct device *dev)
{
	struct unit_directory *ud =
			container_of(dev, struct unit_directory, device);
	struct firedtv *fdtv;
	int kv_len, err;
	void *kv_str;
186 187 188

	kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
	kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
S
Stefan Richter 已提交
189 190 191 192

	fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
	if (!fdtv)
		return -ENOMEM;
193 194 195 196 197

	/*
	 * Work around a bug in udev's path_id script:  Use the fw-host's dev
	 * instead of the unit directory's dev as parent of the input device.
	 */
198
	err = fdtv_register_rc(fdtv, dev->parent->parent);
199 200 201
	if (err)
		goto fail_free;

S
Stefan Richter 已提交
202 203 204
	spin_lock_irq(&node_list_lock);
	list_add_tail(&fdtv->list, &node_list);
	spin_unlock_irq(&node_list_lock);
205

206
	err = avc_identify_subunit(fdtv);
207 208
	if (err)
		goto fail;
G
Greg Kroah-Hartman 已提交
209

S
Stefan Richter 已提交
210
	err = fdtv_dvb_register(fdtv);
211 212
	if (err)
		goto fail;
G
Greg Kroah-Hartman 已提交
213

214
	avc_register_remote_control(fdtv);
215 216
	return 0;
fail:
S
Stefan Richter 已提交
217
	spin_lock_irq(&node_list_lock);
218
	list_del(&fdtv->list);
S
Stefan Richter 已提交
219
	spin_unlock_irq(&node_list_lock);
220
	fdtv_unregister_rc(fdtv);
221
fail_free:
222
	kfree(fdtv);
223
	return err;
G
Greg Kroah-Hartman 已提交
224 225
}

S
Stefan Richter 已提交
226
static int node_remove(struct device *dev)
G
Greg Kroah-Hartman 已提交
227
{
228
	struct firedtv *fdtv = dev->driver_data;
G
Greg Kroah-Hartman 已提交
229

S
Stefan Richter 已提交
230 231 232
	fdtv_dvb_unregister(fdtv);

	spin_lock_irq(&node_list_lock);
233
	list_del(&fdtv->list);
S
Stefan Richter 已提交
234
	spin_unlock_irq(&node_list_lock);
G
Greg Kroah-Hartman 已提交
235

236 237
	cancel_work_sync(&fdtv->remote_ctrl_work);
	fdtv_unregister_rc(fdtv);
G
Greg Kroah-Hartman 已提交
238

239
	kfree(fdtv);
G
Greg Kroah-Hartman 已提交
240 241 242
	return 0;
}

S
Stefan Richter 已提交
243
static int node_update(struct unit_directory *ud)
G
Greg Kroah-Hartman 已提交
244
{
245
	struct firedtv *fdtv = ud->device.driver_data;
G
Greg Kroah-Hartman 已提交
246

247 248 249
	if (fdtv->isochannel >= 0)
		cmp_establish_pp_connection(fdtv, fdtv->subunit,
					    fdtv->isochannel);
G
Greg Kroah-Hartman 已提交
250 251 252
	return 0;
}

253
static struct hpsb_protocol_driver fdtv_driver = {
254
	.name		= "firedtv",
S
Stefan Richter 已提交
255
	.update		= node_update,
G
Greg Kroah-Hartman 已提交
256
	.driver         = {
S
Stefan Richter 已提交
257 258
		.probe  = node_probe,
		.remove = node_remove,
G
Greg Kroah-Hartman 已提交
259 260 261
	},
};

262
static struct hpsb_highlevel fdtv_highlevel = {
263 264 265 266
	.name		= "firedtv",
	.fcp_request	= fcp_request,
};

S
Stefan Richter 已提交
267
int __init fdtv_1394_init(struct ieee1394_device_id id_table[])
G
Greg Kroah-Hartman 已提交
268 269 270
{
	int ret;

271
	hpsb_register_highlevel(&fdtv_highlevel);
S
Stefan Richter 已提交
272
	fdtv_driver.id_table = id_table;
273
	ret = hpsb_register_protocol(&fdtv_driver);
G
Greg Kroah-Hartman 已提交
274
	if (ret) {
275
		printk(KERN_ERR "firedtv: failed to register protocol\n");
276
		hpsb_unregister_highlevel(&fdtv_highlevel);
277 278
	}
	return ret;
G
Greg Kroah-Hartman 已提交
279 280
}

S
Stefan Richter 已提交
281
void __exit fdtv_1394_exit(void)
G
Greg Kroah-Hartman 已提交
282
{
283 284
	hpsb_unregister_protocol(&fdtv_driver);
	hpsb_unregister_highlevel(&fdtv_highlevel);
G
Greg Kroah-Hartman 已提交
285
}