Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31 285 lines 6.8 kB view raw
1/* 2 * FireDTV driver (formerly known as FireSAT) 3 * 4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> 5 * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com> 6 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 */ 13 14#include <linux/device.h> 15#include <linux/errno.h> 16#include <linux/kernel.h> 17#include <linux/list.h> 18#include <linux/spinlock.h> 19#include <linux/types.h> 20 21#include <dma.h> 22#include <csr1212.h> 23#include <highlevel.h> 24#include <hosts.h> 25#include <ieee1394.h> 26#include <iso.h> 27#include <nodemgr.h> 28 29#include "firedtv.h" 30 31static LIST_HEAD(node_list); 32static DEFINE_SPINLOCK(node_list_lock); 33 34#define FIREWIRE_HEADER_SIZE 4 35#define CIP_HEADER_SIZE 8 36 37static void rawiso_activity_cb(struct hpsb_iso *iso) 38{ 39 struct firedtv *f, *fdtv = NULL; 40 unsigned int i, num, packet; 41 unsigned char *buf; 42 unsigned long flags; 43 int count; 44 45 spin_lock_irqsave(&node_list_lock, flags); 46 list_for_each_entry(f, &node_list, list) 47 if (f->backend_data == iso) { 48 fdtv = f; 49 break; 50 } 51 spin_unlock_irqrestore(&node_list_lock, flags); 52 53 packet = iso->first_packet; 54 num = hpsb_iso_n_ready(iso); 55 56 if (!fdtv) { 57 dev_err(fdtv->device, "received at unknown iso channel\n"); 58 goto out; 59 } 60 61 for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) { 62 buf = dma_region_i(&iso->data_buf, unsigned char, 63 iso->infos[packet].offset + CIP_HEADER_SIZE); 64 count = (iso->infos[packet].len - CIP_HEADER_SIZE) / 65 (188 + FIREWIRE_HEADER_SIZE); 66 67 /* ignore empty packet */ 68 if (iso->infos[packet].len <= CIP_HEADER_SIZE) 69 continue; 70 71 while (count--) { 72 if (buf[FIREWIRE_HEADER_SIZE] == 0x47) 73 dvb_dmx_swfilter_packets(&fdtv->demux, 74 &buf[FIREWIRE_HEADER_SIZE], 1); 75 else 76 dev_err(fdtv->device, 77 "skipping invalid packet\n"); 78 buf += 188 + FIREWIRE_HEADER_SIZE; 79 } 80 } 81out: 82 hpsb_iso_recv_release_packets(iso, num); 83} 84 85static inline struct node_entry *node_of(struct firedtv *fdtv) 86{ 87 return container_of(fdtv->device, struct unit_directory, device)->ne; 88} 89 90static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg) 91{ 92 return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data, 93 (__force quadlet_t)arg); 94} 95 96static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len) 97{ 98 return hpsb_node_read(node_of(fdtv), addr, data, len); 99} 100 101static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) 102{ 103 return hpsb_node_write(node_of(fdtv), addr, data, len); 104} 105 106#define FDTV_ISO_BUFFER_PACKETS 256 107#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200) 108 109static int start_iso(struct firedtv *fdtv) 110{ 111 struct hpsb_iso *iso_handle; 112 int ret; 113 114 iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host, 115 FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS, 116 fdtv->isochannel, HPSB_ISO_DMA_DEFAULT, 117 -1, /* stat.config.irq_interval */ 118 rawiso_activity_cb); 119 if (iso_handle == NULL) { 120 dev_err(fdtv->device, "cannot initialize iso receive\n"); 121 return -ENOMEM; 122 } 123 fdtv->backend_data = iso_handle; 124 125 ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0); 126 if (ret != 0) { 127 dev_err(fdtv->device, "cannot start iso receive\n"); 128 hpsb_iso_shutdown(iso_handle); 129 fdtv->backend_data = NULL; 130 } 131 return ret; 132} 133 134static void stop_iso(struct firedtv *fdtv) 135{ 136 struct hpsb_iso *iso_handle = fdtv->backend_data; 137 138 if (iso_handle != NULL) { 139 hpsb_iso_stop(iso_handle); 140 hpsb_iso_shutdown(iso_handle); 141 } 142 fdtv->backend_data = NULL; 143} 144 145static const struct firedtv_backend fdtv_1394_backend = { 146 .lock = node_lock, 147 .read = node_read, 148 .write = node_write, 149 .start_iso = start_iso, 150 .stop_iso = stop_iso, 151}; 152 153static void fcp_request(struct hpsb_host *host, int nodeid, int direction, 154 int cts, u8 *data, size_t length) 155{ 156 struct firedtv *f, *fdtv = NULL; 157 unsigned long flags; 158 int su; 159 160 if (length == 0 || (data[0] & 0xf0) != 0) 161 return; 162 163 su = data[1] & 0x7; 164 165 spin_lock_irqsave(&node_list_lock, flags); 166 list_for_each_entry(f, &node_list, list) 167 if (node_of(f)->host == host && 168 node_of(f)->nodeid == nodeid && 169 (f->subunit == su || (f->subunit == 0 && su == 0x7))) { 170 fdtv = f; 171 break; 172 } 173 spin_unlock_irqrestore(&node_list_lock, flags); 174 175 if (fdtv) 176 avc_recv(fdtv, data, length); 177} 178 179static int node_probe(struct device *dev) 180{ 181 struct unit_directory *ud = 182 container_of(dev, struct unit_directory, device); 183 struct firedtv *fdtv; 184 int kv_len, err; 185 void *kv_str; 186 187 kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); 188 kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); 189 190 fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len); 191 if (!fdtv) 192 return -ENOMEM; 193 194 /* 195 * Work around a bug in udev's path_id script: Use the fw-host's dev 196 * instead of the unit directory's dev as parent of the input device. 197 */ 198 err = fdtv_register_rc(fdtv, dev->parent->parent); 199 if (err) 200 goto fail_free; 201 202 spin_lock_irq(&node_list_lock); 203 list_add_tail(&fdtv->list, &node_list); 204 spin_unlock_irq(&node_list_lock); 205 206 err = avc_identify_subunit(fdtv); 207 if (err) 208 goto fail; 209 210 err = fdtv_dvb_register(fdtv); 211 if (err) 212 goto fail; 213 214 avc_register_remote_control(fdtv); 215 return 0; 216fail: 217 spin_lock_irq(&node_list_lock); 218 list_del(&fdtv->list); 219 spin_unlock_irq(&node_list_lock); 220 fdtv_unregister_rc(fdtv); 221fail_free: 222 kfree(fdtv); 223 return err; 224} 225 226static int node_remove(struct device *dev) 227{ 228 struct firedtv *fdtv = dev_get_drvdata(dev); 229 230 fdtv_dvb_unregister(fdtv); 231 232 spin_lock_irq(&node_list_lock); 233 list_del(&fdtv->list); 234 spin_unlock_irq(&node_list_lock); 235 236 cancel_work_sync(&fdtv->remote_ctrl_work); 237 fdtv_unregister_rc(fdtv); 238 239 kfree(fdtv); 240 return 0; 241} 242 243static int node_update(struct unit_directory *ud) 244{ 245 struct firedtv *fdtv = dev_get_drvdata(&ud->device); 246 247 if (fdtv->isochannel >= 0) 248 cmp_establish_pp_connection(fdtv, fdtv->subunit, 249 fdtv->isochannel); 250 return 0; 251} 252 253static struct hpsb_protocol_driver fdtv_driver = { 254 .name = "firedtv", 255 .update = node_update, 256 .driver = { 257 .probe = node_probe, 258 .remove = node_remove, 259 }, 260}; 261 262static struct hpsb_highlevel fdtv_highlevel = { 263 .name = "firedtv", 264 .fcp_request = fcp_request, 265}; 266 267int __init fdtv_1394_init(struct ieee1394_device_id id_table[]) 268{ 269 int ret; 270 271 hpsb_register_highlevel(&fdtv_highlevel); 272 fdtv_driver.id_table = id_table; 273 ret = hpsb_register_protocol(&fdtv_driver); 274 if (ret) { 275 printk(KERN_ERR "firedtv: failed to register protocol\n"); 276 hpsb_unregister_highlevel(&fdtv_highlevel); 277 } 278 return ret; 279} 280 281void __exit fdtv_1394_exit(void) 282{ 283 hpsb_unregister_protocol(&fdtv_driver); 284 hpsb_unregister_highlevel(&fdtv_highlevel); 285}