aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/firewire/firedtv-fw.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/media/dvb/firewire/firedtv-fw.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/media/dvb/firewire/firedtv-fw.c')
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c147
1 files changed, 119 insertions, 28 deletions
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 7424b0493f9d..864b6274c729 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -9,11 +9,18 @@
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <linux/list.h> 10#include <linux/list.h>
11#include <linux/mm.h> 11#include <linux/mm.h>
12#include <linux/mod_devicetable.h>
13#include <linux/module.h>
14#include <linux/mutex.h>
12#include <linux/slab.h> 15#include <linux/slab.h>
13#include <linux/spinlock.h> 16#include <linux/spinlock.h>
17#include <linux/string.h>
14#include <linux/types.h> 18#include <linux/types.h>
19#include <linux/wait.h>
20#include <linux/workqueue.h>
15 21
16#include <asm/page.h> 22#include <asm/page.h>
23#include <asm/system.h>
17 24
18#include <dvb_demux.h> 25#include <dvb_demux.h>
19 26
@@ -41,17 +48,17 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
41 return rcode != RCODE_COMPLETE ? -EIO : 0; 48 return rcode != RCODE_COMPLETE ? -EIO : 0;
42} 49}
43 50
44static int node_lock(struct firedtv *fdtv, u64 addr, void *data) 51int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data)
45{ 52{
46 return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP); 53 return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
47} 54}
48 55
49static int node_read(struct firedtv *fdtv, u64 addr, void *data) 56int fdtv_read(struct firedtv *fdtv, u64 addr, void *data)
50{ 57{
51 return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST); 58 return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
52} 59}
53 60
54static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) 61int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
55{ 62{
56 return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST); 63 return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
57} 64}
@@ -67,7 +74,7 @@ static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
67#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE) 74#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
68#define IRQ_INTERVAL 16 75#define IRQ_INTERVAL 16
69 76
70struct firedtv_receive_context { 77struct fdtv_ir_context {
71 struct fw_iso_context *context; 78 struct fw_iso_context *context;
72 struct fw_iso_buffer buffer; 79 struct fw_iso_buffer buffer;
73 int interrupt_packet; 80 int interrupt_packet;
@@ -75,7 +82,7 @@ struct firedtv_receive_context {
75 char *pages[N_PAGES]; 82 char *pages[N_PAGES];
76}; 83};
77 84
78static int queue_iso(struct firedtv_receive_context *ctx, int index) 85static int queue_iso(struct fdtv_ir_context *ctx, int index)
79{ 86{
80 struct fw_iso_packet p; 87 struct fw_iso_packet p;
81 88
@@ -92,7 +99,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
92 size_t header_length, void *header, void *data) 99 size_t header_length, void *header, void *data)
93{ 100{
94 struct firedtv *fdtv = data; 101 struct firedtv *fdtv = data;
95 struct firedtv_receive_context *ctx = fdtv->backend_data; 102 struct fdtv_ir_context *ctx = fdtv->ir_context;
96 __be32 *h, *h_end; 103 __be32 *h, *h_end;
97 int length, err, i = ctx->current_packet; 104 int length, err, i = ctx->current_packet;
98 char *p, *p_end; 105 char *p, *p_end;
@@ -118,12 +125,13 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
118 125
119 i = (i + 1) & (N_PACKETS - 1); 126 i = (i + 1) & (N_PACKETS - 1);
120 } 127 }
128 fw_iso_context_queue_flush(ctx->context);
121 ctx->current_packet = i; 129 ctx->current_packet = i;
122} 130}
123 131
124static int start_iso(struct firedtv *fdtv) 132int fdtv_start_iso(struct firedtv *fdtv)
125{ 133{
126 struct firedtv_receive_context *ctx; 134 struct fdtv_ir_context *ctx;
127 struct fw_device *device = device_of(fdtv); 135 struct fw_device *device = device_of(fdtv);
128 int i, err; 136 int i, err;
129 137
@@ -161,7 +169,7 @@ static int start_iso(struct firedtv *fdtv)
161 if (err) 169 if (err)
162 goto fail; 170 goto fail;
163 171
164 fdtv->backend_data = ctx; 172 fdtv->ir_context = ctx;
165 173
166 return 0; 174 return 0;
167fail: 175fail:
@@ -174,9 +182,9 @@ fail_free:
174 return err; 182 return err;
175} 183}
176 184
177static void stop_iso(struct firedtv *fdtv) 185void fdtv_stop_iso(struct firedtv *fdtv)
178{ 186{
179 struct firedtv_receive_context *ctx = fdtv->backend_data; 187 struct fdtv_ir_context *ctx = fdtv->ir_context;
180 188
181 fw_iso_context_stop(ctx->context); 189 fw_iso_context_stop(ctx->context);
182 fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card); 190 fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
@@ -184,14 +192,6 @@ static void stop_iso(struct firedtv *fdtv)
184 kfree(ctx); 192 kfree(ctx);
185} 193}
186 194
187static const struct firedtv_backend backend = {
188 .lock = node_lock,
189 .read = node_read,
190 .write = node_write,
191 .start_iso = start_iso,
192 .stop_iso = stop_iso,
193};
194
195static void handle_fcp(struct fw_card *card, struct fw_request *request, 195static void handle_fcp(struct fw_card *card, struct fw_request *request,
196 int tcode, int destination, int source, int generation, 196 int tcode, int destination, int source, int generation,
197 unsigned long long offset, void *payload, size_t length, 197 unsigned long long offset, void *payload, size_t length,
@@ -238,6 +238,14 @@ static const struct fw_address_region fcp_region = {
238 .end = CSR_REGISTER_BASE + CSR_FCP_END, 238 .end = CSR_REGISTER_BASE + CSR_FCP_END,
239}; 239};
240 240
241static const char * const model_names[] = {
242 [FIREDTV_UNKNOWN] = "unknown type",
243 [FIREDTV_DVB_S] = "FireDTV S/CI",
244 [FIREDTV_DVB_C] = "FireDTV C/CI",
245 [FIREDTV_DVB_T] = "FireDTV T/CI",
246 [FIREDTV_DVB_S2] = "FireDTV S2 ",
247};
248
241/* Adjust the template string if models with longer names appear. */ 249/* Adjust the template string if models with longer names appear. */
242#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????") 250#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
243 251
@@ -245,15 +253,31 @@ static int node_probe(struct device *dev)
245{ 253{
246 struct firedtv *fdtv; 254 struct firedtv *fdtv;
247 char name[MAX_MODEL_NAME_LEN]; 255 char name[MAX_MODEL_NAME_LEN];
248 int name_len, err; 256 int name_len, i, err;
249
250 name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
251 name, sizeof(name));
252 257
253 fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0); 258 fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
254 if (!fdtv) 259 if (!fdtv)
255 return -ENOMEM; 260 return -ENOMEM;
256 261
262 dev_set_drvdata(dev, fdtv);
263 fdtv->device = dev;
264 fdtv->isochannel = -1;
265 fdtv->voltage = 0xff;
266 fdtv->tone = 0xff;
267
268 mutex_init(&fdtv->avc_mutex);
269 init_waitqueue_head(&fdtv->avc_wait);
270 mutex_init(&fdtv->demux_mutex);
271 INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
272
273 name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
274 name, sizeof(name));
275 for (i = ARRAY_SIZE(model_names); --i; )
276 if (strlen(model_names[i]) <= name_len &&
277 strncmp(name, model_names[i], name_len) == 0)
278 break;
279 fdtv->type = i;
280
257 err = fdtv_register_rc(fdtv, dev); 281 err = fdtv_register_rc(fdtv, dev);
258 if (err) 282 if (err)
259 goto fail_free; 283 goto fail_free;
@@ -266,7 +290,7 @@ static int node_probe(struct device *dev)
266 if (err) 290 if (err)
267 goto fail; 291 goto fail;
268 292
269 err = fdtv_dvb_register(fdtv); 293 err = fdtv_dvb_register(fdtv, model_names[fdtv->type]);
270 if (err) 294 if (err)
271 goto fail; 295 goto fail;
272 296
@@ -309,6 +333,60 @@ static void node_update(struct fw_unit *unit)
309 fdtv->isochannel); 333 fdtv->isochannel);
310} 334}
311 335
336#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
337 IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
338
339#define DIGITAL_EVERYWHERE_OUI 0x001287
340#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
341#define AVC_SW_VERSION_ENTRY 0x010001
342
343static const struct ieee1394_device_id fdtv_id_table[] = {
344 {
345 /* FloppyDTV S/CI and FloppyDTV S2 */
346 .match_flags = MATCH_FLAGS,
347 .vendor_id = DIGITAL_EVERYWHERE_OUI,
348 .model_id = 0x000024,
349 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
350 .version = AVC_SW_VERSION_ENTRY,
351 }, {
352 /* FloppyDTV T/CI */
353 .match_flags = MATCH_FLAGS,
354 .vendor_id = DIGITAL_EVERYWHERE_OUI,
355 .model_id = 0x000025,
356 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
357 .version = AVC_SW_VERSION_ENTRY,
358 }, {
359 /* FloppyDTV C/CI */
360 .match_flags = MATCH_FLAGS,
361 .vendor_id = DIGITAL_EVERYWHERE_OUI,
362 .model_id = 0x000026,
363 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
364 .version = AVC_SW_VERSION_ENTRY,
365 }, {
366 /* FireDTV S/CI and FloppyDTV S2 */
367 .match_flags = MATCH_FLAGS,
368 .vendor_id = DIGITAL_EVERYWHERE_OUI,
369 .model_id = 0x000034,
370 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
371 .version = AVC_SW_VERSION_ENTRY,
372 }, {
373 /* FireDTV T/CI */
374 .match_flags = MATCH_FLAGS,
375 .vendor_id = DIGITAL_EVERYWHERE_OUI,
376 .model_id = 0x000035,
377 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
378 .version = AVC_SW_VERSION_ENTRY,
379 }, {
380 /* FireDTV C/CI */
381 .match_flags = MATCH_FLAGS,
382 .vendor_id = DIGITAL_EVERYWHERE_OUI,
383 .model_id = 0x000036,
384 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
385 .version = AVC_SW_VERSION_ENTRY,
386 }, {}
387};
388MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
389
312static struct fw_driver fdtv_driver = { 390static struct fw_driver fdtv_driver = {
313 .driver = { 391 .driver = {
314 .owner = THIS_MODULE, 392 .owner = THIS_MODULE,
@@ -321,7 +399,7 @@ static struct fw_driver fdtv_driver = {
321 .id_table = fdtv_id_table, 399 .id_table = fdtv_id_table,
322}; 400};
323 401
324int __init fdtv_fw_init(void) 402static int __init fdtv_init(void)
325{ 403{
326 int ret; 404 int ret;
327 405
@@ -329,11 +407,24 @@ int __init fdtv_fw_init(void)
329 if (ret < 0) 407 if (ret < 0)
330 return ret; 408 return ret;
331 409
332 return driver_register(&fdtv_driver.driver); 410 ret = driver_register(&fdtv_driver.driver);
411 if (ret < 0)
412 fw_core_remove_address_handler(&fcp_handler);
413
414 return ret;
333} 415}
334 416
335void fdtv_fw_exit(void) 417static void __exit fdtv_exit(void)
336{ 418{
337 driver_unregister(&fdtv_driver.driver); 419 driver_unregister(&fdtv_driver.driver);
338 fw_core_remove_address_handler(&fcp_handler); 420 fw_core_remove_address_handler(&fcp_handler);
339} 421}
422
423module_init(fdtv_init);
424module_exit(fdtv_exit);
425
426MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
427MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
428MODULE_DESCRIPTION("FireDTV DVB Driver");
429MODULE_LICENSE("GPL");
430MODULE_SUPPORTED_DEVICE("FireDTV DVB");