/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to pci.c

  • Committer: Suren A. Chilingaryan
  • Date: 2011-04-12 00:57:02 UTC
  • Revision ID: csa@dside.dyndns.org-20110412005702-ir1cch0f1feop7ay
Infrastructure for event API

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#define _PCILIB_PCI_C
 
2
#define _POSIX_C_SOURCE 199309L
2
3
 
3
4
#include <stdio.h>
4
5
#include <string.h>
17
18
#include "tools.h"
18
19
 
19
20
#include "pci.h"
20
 
#include "ipecamera.h"
 
21
#include "ipecamera/model.h"
21
22
#include "error.h"
22
23
 
23
24
#define BIT_MASK(bits) ((1l << (bits)) - 1)
34
35
 
35
36
    pcilib_bar_t reg_bar;
36
37
    char *reg_space;
 
38
 
 
39
    pcilib_bar_t data_bar;
 
40
    char *data_space;
 
41
    size_t data_size;
 
42
    
 
43
    void *event_ctx;
37
44
    
38
45
#ifdef PCILIB_FILE_IO
39
46
    int file_io_handle;
60
67
}
61
68
 
62
69
pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
 
70
    pcilib_event_api_description_t *api;
63
71
    pcilib_t *ctx = malloc(sizeof(pcilib_t));
64
72
 
65
73
    if (ctx) {
67
75
        ctx->page_mask = (uintptr_t)-1;
68
76
        ctx->model = model;
69
77
        ctx->reg_space = NULL;
 
78
 
 
79
        if (!model) model = pcilib_get_model(ctx);
 
80
        api = pcilib_model[model].event_api;
 
81
        if ((api)&&(api->init)) ctx->event_ctx = api->init(ctx);
70
82
    }
71
83
 
72
84
    return ctx;
297
309
            }
298
310
        }
299
311
        
300
 
        return -1;
301
 
    }
302
 
    
303
 
    return 0;
304
 
}
305
 
            
 
312
        return PCILIB_ERROR_NOTFOUND;
 
313
    }
 
314
    
 
315
    return 0;
 
316
}
 
317
 
 
318
static int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) {
 
319
    int err;
 
320
    int i;
 
321
    
 
322
    if (!ctx->data_space) {
 
323
        const pci_board_info *board_info = pcilib_get_board_info(ctx);
 
324
 
 
325
        err = pcilib_map_register_space(ctx);
 
326
        if (err) {
 
327
            pcilib_error("Error mapping register space");
 
328
            return err;
 
329
        }
 
330
        
 
331
        if (addr) {
 
332
        }
 
333
        
 
334
        int data_bar = -1;      
 
335
        
 
336
        for (i = 0; i < PCILIB_MAX_BANKS; i++) {
 
337
            if ((i == ctx->reg_bar)||(!board_info->bar_length[i])) continue;
 
338
            
 
339
            if (addr) {
 
340
                if (board_info->bar_start[i] == addr) {
 
341
                    data_bar = i;
 
342
                    break;
 
343
                }
 
344
            } else {
 
345
                if (data_bar >= 0) {
 
346
                    data_bar = -1;
 
347
                    break;
 
348
                }
 
349
                
 
350
                data_bar = i;
 
351
            }
 
352
        }
 
353
            
 
354
 
 
355
        if (data_bar < 0) {
 
356
            if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr);
 
357
            else pcilib_error("Unable to find the data space");
 
358
            return PCILIB_ERROR_NOTFOUND;
 
359
        }
 
360
        
 
361
        ctx->data_bar = data_bar;
 
362
        ctx->data_space = pcilib_map_bar(ctx, data_bar);
 
363
        ctx->data_size = board_info->bar_length[data_bar];
 
364
        
 
365
        if (!ctx->data_space) {
 
366
            pcilib_error("Unable to map the data space");
 
367
            return PCILIB_ERROR_FAILED;
 
368
        }
 
369
    }
 
370
    
 
371
    return 0;
 
372
}
306
373
        
307
374
static void pcilib_unmap_register_space(pcilib_t *ctx) {
308
375
    if (ctx->reg_space) {
311
378
    }
312
379
}
313
380
 
 
381
static void pcilib_unmap_data_space(pcilib_t *ctx) {
 
382
    if (ctx->data_space) {
 
383
        pcilib_unmap_bar(ctx, ctx->data_bar, ctx->data_space);
 
384
        ctx->data_space = NULL;
 
385
    }
 
386
}
 
387
 
314
388
char  *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) {
315
389
    size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
316
390
    if (offset < ctx->board_info.bar_length[ctx->reg_bar]) {
319
393
    return NULL;
320
394
}
321
395
 
 
396
char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
 
397
    int err;
 
398
    
 
399
    err = pcilib_map_data_space(ctx, addr);
 
400
    if (err) {
 
401
        pcilib_error("Failed to map the specified address space (%lx)", addr);
 
402
        return NULL;
 
403
    }
 
404
    
 
405
    if (size) *size = ctx->data_size;    
 
406
    
 
407
    return ctx->data_space + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask);
 
408
}
 
409
 
322
410
 
323
411
void pcilib_close(pcilib_t *ctx) {
324
412
    if (ctx) {
 
413
        pcilib_model_t model = pcilib_get_model(ctx);
 
414
        pcilib_event_api_description_t *api = pcilib_model[model].event_api;
 
415
    
 
416
        if ((api)&&(api->free)) api->free(ctx->event_ctx);
 
417
        if (ctx->data_space) pcilib_unmap_data_space(ctx);
325
418
        if (ctx->reg_space) pcilib_unmap_register_space(ctx);
326
419
        close(ctx->handle);
 
420
        
327
421
        free(ctx);
328
422
    }
329
423
}
491
585
        pcilib_error("Big-endian byte order support is not implemented");
492
586
        return PCILIB_ERROR_NOTSUPPORTED;
493
587
    } else {
494
 
        for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
495
 
            buf[i] = res & BIT_MASK(b->access);
496
 
            res >>= b->access;
497
 
        }
 
588
        if (b->access == sizeof(res) * 8) {
 
589
            buf[i] = res;
 
590
        } else {
 
591
            for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
 
592
                buf[i] = res & BIT_MASK(b->access);
 
593
                res >>= b->access;
 
594
            }
498
595
        
499
 
        if (res) {
500
 
            pcilib_error("Value %i is to big to fit in the register %s", value, r->name);
501
 
            return PCILIB_ERROR_OUTOFRANGE;
 
596
            if (res) {
 
597
                pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
 
598
                return PCILIB_ERROR_OUTOFRANGE;
 
599
            }
502
600
        }
503
601
    }
504
 
    
 
602
 
505
603
    err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
506
604
    return err;
507
605
}
511
609
    int reg;
512
610
    
513
611
    reg = pcilib_find_register(ctx, bank, regname);
514
 
    if (reg < 0) pcilib_error("Register (%s) is not found", regname);
 
612
    if (reg < 0) {
 
613
        pcilib_error("Register (%s) is not found", regname);
 
614
        return PCILIB_ERROR_NOTFOUND;
 
615
    }
515
616
 
516
617
    return pcilib_write_register_by_id(ctx, reg, value);
517
618
}
518
619
 
 
620
 
 
621
int pcilib_reset(pcilib_t *ctx) {
 
622
    pcilib_event_api_description_t *api;
 
623
    
 
624
    pcilib_model_t model = pcilib_get_model(ctx);
 
625
 
 
626
    api = pcilib_model[model].event_api;
 
627
    if (!api) {
 
628
        pcilib_error("Event API is not supported by the selected model");
 
629
        return PCILIB_ERROR_NOTSUPPORTED;
 
630
    }
 
631
    
 
632
    if (api->reset) 
 
633
        return api->reset(ctx->event_ctx);
 
634
        
 
635
    return 0;
 
636
}
 
637
 
 
638
int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
 
639
    pcilib_event_api_description_t *api;
 
640
    
 
641
    pcilib_model_t model = pcilib_get_model(ctx);
 
642
 
 
643
    api = pcilib_model[model].event_api;
 
644
    if (!api) {
 
645
        pcilib_error("Event API is not supported by the selected model");
 
646
        return PCILIB_ERROR_NOTSUPPORTED;
 
647
    }
 
648
 
 
649
    if (api->start) 
 
650
        return api->start(ctx->event_ctx, event_mask, callback, user);
 
651
 
 
652
    return 0;
 
653
}
 
654
 
 
655
int pcilib_stop(pcilib_t *ctx) {
 
656
    pcilib_event_api_description_t *api;
 
657
    
 
658
    pcilib_model_t model = pcilib_get_model(ctx);
 
659
 
 
660
    api = pcilib_model[model].event_api;
 
661
    if (!api) {
 
662
        pcilib_error("Event API is not supported by the selected model");
 
663
        return PCILIB_ERROR_NOTSUPPORTED;
 
664
    }
 
665
 
 
666
    if (api->stop) 
 
667
        return api->stop(ctx->event_ctx);
 
668
 
 
669
    return 0;
 
670
}
 
671
 
 
672
int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
 
673
    pcilib_event_api_description_t *api;
 
674
    
 
675
    pcilib_model_t model = pcilib_get_model(ctx);
 
676
 
 
677
    api = pcilib_model[model].event_api;
 
678
    if (!api) {
 
679
        pcilib_error("Event API is not supported by the selected model");
 
680
        return PCILIB_ERROR_NOTSUPPORTED;
 
681
    }
 
682
 
 
683
    if (api->trigger) 
 
684
        return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
 
685
 
 
686
    pcilib_error("Self triggering is not supported by the selected model");
 
687
    return PCILIB_ERROR_NOTSUPPORTED;
 
688
}
 
689
 
 
690
 
 
691
void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
 
692
    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
 
693
    if (!api) {
 
694
        pcilib_error("Event API is not supported by the selected model");
 
695
        return NULL;
 
696
    }
 
697
 
 
698
    if (api->get_data) 
 
699
        return api->get_data(ctx->event_ctx, event_id, data_type, size);
 
700
 
 
701
    return NULL;
 
702
}
 
703
 
 
704
int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
 
705
    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
 
706
    if (!api) {
 
707
        pcilib_error("Event API is not supported by the selected model");
 
708
        return PCILIB_ERROR_NOTSUPPORTED;
 
709
    }
 
710
 
 
711
    if (api->return_data) 
 
712
        return api->return_data(ctx->event_ctx, event_id);
 
713
 
 
714
    return 0;
 
715
}
 
716
 
 
717
 
 
718
typedef struct {
 
719
    pcilib_t *ctx;
 
720
    
 
721
    size_t *size;
 
722
    void **data;
 
723
} pcilib_grab_callback_user_data_t;
 
724
 
 
725
static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
 
726
    int err;
 
727
    void *data;
 
728
    size_t size;
 
729
    int allocated = 0;
 
730
 
 
731
    pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
 
732
 
 
733
    data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
 
734
    if (!data) {
 
735
        pcilib_error("Error getting event data");
 
736
        return PCILIB_ERROR_FAILED;
 
737
    }
 
738
    
 
739
    if (*(user->data)) {
 
740
        if ((user->size)&&(*(user->size) < size)) {
 
741
            pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
 
742
            return PCILIB_ERROR_MEMORY;
 
743
        }
 
744
 
 
745
        *(user->size) = size;
 
746
    } else {
 
747
        *(user->data) = malloc(size);
 
748
        if (!*(user->data)) {
 
749
            pcilib_error("Memory allocation (%i bytes) for event data is failed");
 
750
            return PCILIB_ERROR_MEMORY;
 
751
        }
 
752
        if (*(user->size)) *(user->size) = size;
 
753
        allocated = 1;
 
754
    }
 
755
    
 
756
    memcpy(*(user->data), data, size);
 
757
    
 
758
    err = pcilib_return_data(user->ctx, event_id);
 
759
    if (err) {
 
760
        if (allocated) {
 
761
            free(*(user->data));
 
762
            *(user->data) = NULL;
 
763
        }
 
764
        pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
 
765
        return err;
 
766
    }
 
767
    
 
768
    return 0;
 
769
}
 
770
 
 
771
int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
 
772
    int err;
 
773
    
 
774
    pcilib_grab_callback_user_data_t user = {ctx, size, data};
 
775
    
 
776
    err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
 
777
    if (!err) {
 
778
        if (timeout) nanosleep(timeout, NULL);
 
779
        else err = pcilib_trigger(ctx, event_mask, 0, NULL);
 
780
    }
 
781
    pcilib_stop(ctx);
 
782
    return 0;
 
783
}