OpenCores
URL https://opencores.org/ocsvn/pci/pci/trunk

Subversion Repositories pci

[/] [pci/] [tags/] [rel_00/] [apps/] [sw/] [driver/] [spartan_drv.c] - Blame information for rev 154

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 21 mihad
 
2
#define __KERNEL__
3
#define MODULE
4
 
5
#include <linux/module.h>
6
#include <linux/errno.h>
7
#include <linux/kernel.h>
8
#include <linux/pci.h>
9
 
10
#include <asm/uaccess.h>
11
#include <spartan_kint.h> //IOCTL definitions
12
 
13
// define vendor and device ID here - currently this definitions specify reference designs from insight electronic
14
#ifdef __SDRAM__
15
#define OC_PCI_VENDOR 0x1597
16
#define OC_PCI_DEVICE 0x0300
17
#endif
18
#ifdef __VGA__
19
#define OC_PCI_VENDOR 0x2321
20
#define OC_PCI_DEVICE 0x0001
21
#endif
22
 
23
// if someone wants specific major number assigned to spartan board - specify it here 
24
// if 0 is used, kernel assigns it automaticaly
25
#ifdef __SDRAM__
26
#define REQUESTED_MAJOR 243
27
#endif
28
 
29
#ifdef __VGA__
30
#define REQUESTED_MAJOR 244
31
#endif
32
 
33
// if compiling module for kernel 2.4 - leave this defined
34
// for kernel 2.2 - comment this out
35
#define KERNEL_VER_24
36
 
37
#ifndef SEEK_SET
38
        #define SEEK_SET 0
39
        #define SEEK_CUR 1
40
        #define SEEK_END 2
41
#endif
42
 
43
// io.h needed just for kernel 2.2
44
#ifndef KERNEL_VER_24
45
        #include <asm/io.h>
46
#endif
47
 
48
// memory mapped or IO mapped region definitions
49
#define SPARTAN_MEM_MAPPED 0
50
#define SPARTAN_IO_MAPPED 1
51
 
52
#ifdef __VGA__
53
#define VIDEO_SZ (640*480)
54
#endif
55
 
56
// structure for holding board information
57
// (6 base addresses, mapping, page etc.
58
static struct our_dev
59
{
60
        int major ;
61
        u32 bases[6] ;
62
        u8 num_of_bases ;
63
        u32 base_size[6] ;
64
        u32 offset ;
65
        u32 page_addr ;
66
        u32 base_page_offset ;
67
        int current_resource ;
68
        int base_map[6] ;
69
        u32 video_base ;
70
        u32 video_vbase ;
71
        u32 video_size ;
72
        struct pci_dev *ppci_spartan_dev ;
73
} pspartan_dev ;
74
 
75
// function prototypes
76
int spartan_open(struct inode *inode, struct file *filp);
77
 
78
int spartan_release(struct inode *inode, struct file *filp);
79
 
80
ssize_t spartan_read(struct file *filp, char *buf, size_t count, loff_t *offset ) ;
81
ssize_t spartan_write(struct file *filp, const char *buf, size_t count, loff_t *offset) ;
82
int     spartan_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg) ;
83
loff_t  spartan_seek(struct file *filp, loff_t offset, int what) ;
84
 
85
// file operations structure - different for kernels 2.2 and 2.4
86
static struct file_operations *pspartan_fops ;
87
static struct file_operations spartan_fops = {
88
        #ifdef KERNEL_VER_24
89
        NULL,
90
        #endif
91
        spartan_seek,
92
        spartan_read,
93
        spartan_write,
94
        NULL,
95
        NULL,
96
        spartan_ioctl,
97
        NULL,
98
        spartan_open,
99
        NULL,
100
        spartan_release,
101
} ;
102
 
103
int open_mem_mapped(void) ;
104
 
105
// seek file operation function
106
loff_t  spartan_seek(struct file *filp, loff_t offset, int origin)
107
{
108
        loff_t requested_offset ;
109
        int resource_num = pspartan_dev.current_resource ;
110
 
111
        switch (origin)
112
        {
113
                case SEEK_CUR:requested_offset = pspartan_dev.offset + offset ; break ;
114
                case SEEK_END:requested_offset = pspartan_dev.base_size[resource_num] + offset ; break ;
115
                default:requested_offset  = offset ; break ;
116
        }
117
 
118
        if ((requested_offset < 0) || (requested_offset > pspartan_dev.base_size[resource_num]))
119
                return -EFAULT ;
120
 
121
        pspartan_dev.offset = requested_offset ;
122
 
123
        return requested_offset ;
124
}
125
 
126
// ioctl for device
127
// currently just a few operations are supported here - defined in spartan_kint.h header
128
int     spartan_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg)
129
{
130
        int error = 0;
131
        int size = _IOC_SIZE(cmd) ;
132
        unsigned long base ;
133
        unsigned long base_size ;
134
        int i;
135
 
136
        if (_IOC_TYPE(cmd) != SPARTAN_IOC_NUM) return -EINVAL ;
137
        if (_IOC_NR(cmd) > SPARTAN_IOC_MAX_NUM) return -EINVAL ;
138
 
139
        // Writes through pointers not allowed - writes only through argument 
140
        if (_IOC_DIR(cmd) & _IOC_WRITE) return -EINVAL ;
141
        else if (_IOC_DIR(cmd) & _IOC_READ)
142
                error = verify_area(VERIFY_WRITE, (void *) arg, size) ;
143
 
144
        if (error)
145
                return error ;
146
 
147
        switch (cmd){
148
                case SPARTAN_IOC_CURRESGET:
149
                        // current resource - they start at 1
150
                        return (pspartan_dev.current_resource + 1) ;
151
                case SPARTAN_IOC_CURRESSET:
152
                        // check if resource is in a range of implemented resources
153
                        if (arg < 0 )
154
                                return -EINVAL ;
155
 
156
                        // unmap previous resource if it was mapped
157
                        if (pspartan_dev.current_resource >= 0)
158
                        {
159
                                iounmap((void *)pspartan_dev.page_addr) ;
160
                        }
161
 
162
                        if (arg == 0)
163
                        {
164
                                // previous resource unmaped - that's all
165
                                pspartan_dev.current_resource = -1 ;
166
                                return 0 ;
167
                        }
168
 
169
                        if (pspartan_dev.num_of_bases < arg)
170
                                return -ENODEV ;
171
 
172
                        // IO mapped not supported yet
173
                        if (pspartan_dev.base_map[arg] == SPARTAN_IO_MAPPED)
174
                        {
175
                                // set current resource to none, since it was unmapped
176
                                pspartan_dev.current_resource = -1 ;
177
                                return -ENODEV ;
178
                        }
179
                        pspartan_dev.current_resource= (int)(arg-1) ;
180
                        // remap new resource
181
                        if ( (error = open_mem_mapped()) )
182
                        {
183
                                pspartan_dev.current_resource = -1 ;
184
                                return error ;
185
                        }
186
                        return 0 ;
187
                case SPARTAN_IOC_CURBASE:
188
                        // check if any resource is currently activated
189
                        if (pspartan_dev.current_resource>=0)
190
                                base = pspartan_dev.bases[pspartan_dev.current_resource] ;
191
                        else
192
                                base = 0x00000000 ;
193
 
194
                        *(unsigned long *)arg = base ;
195
                        return 0 ;
196
                case SPARTAN_IOC_CURBASEMAP:
197
                        // check if any resource is currently activated
198
                        if (pspartan_dev.current_resource>=0)
199
                                base = pspartan_dev.page_addr ;
200
                        else
201
                                base = 0x00000000 ;
202
 
203
                        *(unsigned long *)arg = base ;
204
 
205
                        return 0 ;
206
                case SPARTAN_IOC_CURBASESIZE:
207
                        // check if any resource is currently activated
208
                        if (pspartan_dev.current_resource>=0)
209
                                base_size = pspartan_dev.base_size[pspartan_dev.current_resource] ;
210
                        else
211
                                base_size = 0x00000000 ;
212
 
213
                        *(unsigned long *)arg = base_size ;
214
                        return 0 ;
215
                case SPARTAN_IOC_NUMOFRES:
216
                        return (pspartan_dev.num_of_bases) ;
217
#ifdef __VGA__          
218
                case SPARTAN_IOC_VIDEO_BASE:
219
                        *((unsigned long *)arg) = pspartan_dev.video_base;
220
                        put_user(pspartan_dev.video_base, ((unsigned long *)arg));
221
                        return 0 ;
222
 
223
                case SPARTAN_IOC_VIDEO_VBASE:
224
                        *(unsigned long *)arg = pspartan_dev.video_vbase;
225
                        put_user(pspartan_dev.video_vbase, ((unsigned long *)arg));
226
                        return 0 ;
227
 
228
                case SPARTAN_IOC_VIDEO_SIZE:
229
                        *(unsigned long *)arg = pspartan_dev.video_size;
230
                        put_user(pspartan_dev.video_size, ((unsigned long *)arg));
231
                        return 0;
232
 
233
                case SPARTAN_IOC_SET_VIDEO_BUFF:
234
                        for(i = 0; i < VIDEO_SZ; i++) {
235
                                get_user(*((char *)(pspartan_dev.video_vbase +  i)), ((char *)(arg + i)));
236
                        }
237
 
238
                        return 0;
239
#endif
240
                default:
241
                        return -EINVAL ;
242
        }
243
}
244
 
245
// helper function for memory remaping
246
int open_mem_mapped(void)
247
{
248
        int resource_num = pspartan_dev.current_resource ;
249
        unsigned long num_of_pages = 0 ;
250
        unsigned long base = pspartan_dev.bases[resource_num] ;
251
        unsigned long size = pspartan_dev.base_size[resource_num] ;
252
 
253
        if (!(num_of_pages = (unsigned long)(size/PAGE_SIZE))) ;
254
                num_of_pages++ ;
255
 
256
        pspartan_dev.base_page_offset = base & ~PAGE_MASK ;
257
 
258
        if ((pspartan_dev.base_page_offset + size) < (num_of_pages*PAGE_SIZE))
259
                num_of_pages++ ;
260
 
261
        // remap memory mapped space
262
        pspartan_dev.page_addr = (unsigned long)ioremap(base & PAGE_MASK, num_of_pages * PAGE_SIZE) ;
263
 
264
        if (pspartan_dev.page_addr == 0x00000000)
265
                return -ENOMEM ;
266
 
267
        return 0 ;
268
}
269
 
270
// add io mapped resource handler here
271
int open_io_mapped( void )
272
{
273
        return 0 ;
274
}
275
 
276
// open file operation function
277
int spartan_open(struct inode *inode, struct file *filp)
278
{
279
        if (MOD_IN_USE)
280
                return -EBUSY ;
281
 
282
        pspartan_fops = &spartan_fops ;
283
        filp->f_op = pspartan_fops ;
284
        pspartan_dev.offset = 0 ;
285
        pspartan_dev.current_resource = -1 ;
286
        MOD_INC_USE_COUNT ;
287
        return 0 ;
288
}
289
 
290
// release - called by close on file descriptor
291
int spartan_release(struct inode *inode, struct file *filp)
292
{
293
        // unmap any remaped pages
294
        if (pspartan_dev.current_resource >= 0)
295
                iounmap((void *)pspartan_dev.page_addr) ;
296
 
297
        pspartan_dev.current_resource = -1 ;
298
 
299
        MOD_DEC_USE_COUNT ;
300
        return 0 ;
301
}
302
 
303
// memory mapped resource read function
304
ssize_t spartan_read(struct file *filp, char *buf, size_t count, loff_t *offset_out )
305
{
306
 
307
        unsigned long current_address = pspartan_dev.page_addr + pspartan_dev.base_page_offset + pspartan_dev.offset ;
308
        unsigned long actual_count ;
309
        unsigned long offset = pspartan_dev.offset ;
310
        int resource_num = pspartan_dev.current_resource ;
311
        int i;
312
        int value;
313
 
314
        unsigned long size   = pspartan_dev.base_size[resource_num] ;
315
        int result ;
316
 
317
        if (pspartan_dev.current_resource < 0)
318
                return -ENODEV ;
319
 
320
        if (offset == size)
321
                return 0 ;
322
 
323
        if ( (offset + count) > size )
324
                actual_count = size - offset ;
325
        else
326
                actual_count = count ;
327
 
328
        // verify range if it is OK to copy from
329
        if ((result = verify_area(VERIFY_WRITE, buf, actual_count)))
330
                return result ;
331
 
332
        i = actual_count/4;
333
        while(i--) {
334
 
335
                value = readl(current_address);
336
                put_user(value, ((int *)buf));
337
                buf += 4;
338
                current_address += 4;
339
        }
340
 
341
        pspartan_dev.offset = pspartan_dev.offset + actual_count ;
342
 
343
        *(offset_out) = pspartan_dev.offset ;
344
 
345
        return actual_count ;
346
 }
347
 
348
// memory mapped resource write function
349
ssize_t spartan_write(struct file *filp, const char *buf, size_t count, loff_t *offset_out)
350
{
351
        unsigned long current_address = pspartan_dev.page_addr + pspartan_dev.base_page_offset + pspartan_dev.offset ;
352
        unsigned long actual_count ;
353
        unsigned long offset = pspartan_dev.offset ;
354
        int resource_num = pspartan_dev.current_resource ;
355
        int i;
356
        int value;
357
        unsigned long size   = pspartan_dev.base_size[resource_num] ;
358
        int result ;
359
 
360
        if (pspartan_dev.current_resource < 0)
361
                return -ENODEV ;
362
 
363
        if (offset == size)
364
                return 0 ;
365
 
366
        if ( (offset + count) > size )
367
                actual_count = size - offset ;
368
        else
369
                actual_count = count ;
370
 
371
        // verify range if it is OK to copy from
372
        if ((result = verify_area(VERIFY_READ, buf, actual_count)))
373
                return result ;
374
 
375
        i = actual_count/4;
376
        while(i--) {
377
                get_user(value, ((int *)buf));
378
                writel(value, current_address);
379
                buf += 4;
380
                current_address += 4;
381
        }
382
        pspartan_dev.offset = pspartan_dev.offset + actual_count ;
383
 
384
        *(offset_out) = pspartan_dev.offset ;
385
 
386
        return actual_count ;
387
}
388
 
389
// initialization function - different for 2.2 and 2.4 kernel because of different pci_dev structure
390
int init_module(void)
391
{
392
        int result ;
393
        u32 base_address ;
394
        unsigned long size ;
395
        unsigned short num_of_bases ;
396
        u16 wvalue ;
397
        struct pci_dev *ppci_spartan_dev = NULL ;
398
        struct resource spartan_resource ;
399
        struct page *page;
400
        int sz ;
401
 
402
        if(!pci_present())
403
        {
404
                printk("<1> Kernel reports no PCI bus support!\n " );
405
                return -ENODEV;
406
        }
407
 
408
        if((ppci_spartan_dev = pci_find_device(OC_PCI_VENDOR, OC_PCI_DEVICE, ppci_spartan_dev))==NULL )
409
        {
410
                printk("<1> Device not found!\n " );
411
                return -ENODEV ;
412
        }
413
 
414
        pspartan_dev.ppci_spartan_dev = ppci_spartan_dev ;
415
 
416
#ifdef KERNEL_VER_24
417
        //printk("<1> Board found at address 0x%08X\n", ppci_spartan_dev->resource[0].start) ;
418
        // copy implemented base addresses to private structure
419
 
420
        spartan_resource = ppci_spartan_dev->resource[0] ;
421
        base_address     =  spartan_resource.start ;
422
        printk("<1> First base address register found at %08X \n ", base_address );
423
        num_of_bases = 0 ;
424
        while ((base_address != 0x00000000) && (num_of_bases < 6))
425
        {
426
                pspartan_dev.bases[num_of_bases] = spartan_resource.start ;
427
                pspartan_dev.base_size[num_of_bases] = spartan_resource.end - spartan_resource.start + 1 ;
428
                // check if resource is IO mapped
429
                if (spartan_resource.flags & IORESOURCE_IO)
430
                        pspartan_dev.base_map[num_of_bases] = SPARTAN_IO_MAPPED ;
431
                else
432
                        pspartan_dev.base_map[num_of_bases] = SPARTAN_MEM_MAPPED ;
433
 
434
                num_of_bases++ ;
435
                spartan_resource = ppci_spartan_dev->resource[num_of_bases] ;
436
                base_address = spartan_resource.start ;
437
        }
438
 
439
        result = pci_read_config_word(ppci_spartan_dev, PCI_COMMAND, &wvalue) ;
440
        if (result <  0)
441
        {
442
                printk("<1> Read from command register failed! \n " );
443
                return result ;
444
        }
445
 
446
        result = pci_write_config_word(ppci_spartan_dev, PCI_COMMAND, wvalue | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) ;
447
 
448
        if (result <  0)
449
        {
450
                printk("<1>Write to command register failed! \n " );
451
                return result ;
452
        }
453
 
454
#else
455
 
456
        printk("<1> Board found at address 0x%08X\n", ppci_spartan_dev->base_address[0]);
457
 
458
        // now go through base addresses of development board 
459
        // and see what size they are - first disable devices response
460
        result = pci_read_config_word(ppci_spartan_dev, PCI_COMMAND, &wvalue) ;
461
        if (result <  0)
462
        {
463
                printk("<1> Read from command register failed! \n " );
464
                return result ;
465
        }
466
 
467
        // write masked config value back to command register to 
468
        // disable devices response! mask value
469
        result = pci_write_config_word(ppci_spartan_dev, PCI_COMMAND, wvalue & ~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY) ;
470
 
471
        if (result <  0)
472
        {
473
                printk("<1>Write to command register failed! \n " );
474
                return result ;
475
        }
476
 
477
        // write to base address registers and read back until all 0s are read
478
        base_address = ppci_spartan_dev->base_address[0] ;
479
        num_of_bases = 0 ;
480
        while ((base_address != 0x00000000) && (num_of_bases < 6))
481
        {
482
                // copy non-zero base address to private structure
483
                pspartan_dev.bases[num_of_bases] = ppci_spartan_dev->base_address[num_of_bases] ;
484
 
485
                // write to current register
486
                result = pci_write_config_dword(ppci_spartan_dev, PCI_BASE_ADDRESS_0 + (num_of_bases * 4), 0xFFFFFFFF) ;
487
 
488
                if (result <  0)
489
                {
490
                        printk("<1>Write to BAR%d failed! \n ", num_of_bases);
491
                        return result ;
492
                }
493
 
494
                result = pci_read_config_dword(ppci_spartan_dev, PCI_BASE_ADDRESS_0 + (num_of_bases * 4), &base_address) ;
495
                if (result <  0)
496
                {
497
                        printk("<1>Read from BAR%d failed! \n ", num_of_bases);
498
                        return result ;
499
                }
500
 
501
                // calculate size of this base address register's range
502
                size = 0xFFFFFFFF - base_address ;
503
 
504
                // store size in structure
505
                pspartan_dev.base_size[num_of_bases] = size + 1;
506
 
507
                // set base address back to original value
508
                base_address = pspartan_dev.bases[num_of_bases] ;
509
 
510
                // now write original base address back to this register
511
                result = pci_write_config_dword(ppci_spartan_dev, PCI_BASE_ADDRESS_0 + (num_of_bases * 4), base_address) ;
512
 
513
                if (result <  0)
514
                {
515
                        printk("<1>Write to BAR%d failed! \n ", num_of_bases);
516
                        return result ;
517
                }
518
                num_of_bases++ ;
519
                // read new base address
520
                base_address = ppci_spartan_dev->base_address[num_of_bases] ;
521
 
522
        }
523
        // write original value back to command register!
524
        result = pci_write_config_word(ppci_spartan_dev, PCI_COMMAND, wvalue) ;
525
 
526
        if (result <  0)
527
        {
528
                printk("<1>Write to command register failed! \n " );
529
                return result ;
530
        }
531
#endif
532
        if (num_of_bases < 1)
533
                printk("<1>No implemented base address registers found! \n ") ;
534
 
535
        pspartan_dev.current_resource = - 1 ;
536
 
537
        // store number of bases in structure
538
        pspartan_dev.num_of_bases = num_of_bases ;
539
 
540
        // display information about all base addresses found in this procedure
541
        for (num_of_bases = 0; num_of_bases < pspartan_dev.num_of_bases; num_of_bases++)
542
        {
543
                printk("<1>BAR%d range from %08X to %08X \n ", num_of_bases, pspartan_dev.bases[num_of_bases], pspartan_dev.bases[num_of_bases] + pspartan_dev.base_size[num_of_bases]);
544
        }
545
#ifdef __VGA__
546
        for (sz = 0, size = PAGE_SIZE; size < VIDEO_SZ; sz++, size <<= 1);
547
        pspartan_dev.video_vbase = __get_free_pages(GFP_KERNEL, sz);
548
 
549
        if (pspartan_dev.video_vbase == 0) {
550
                printk(KERN_ERR "spartan: abort, cannot allocate video memory\n");
551
                return -EIO;
552
        }
553
 
554
        pspartan_dev.video_size = PAGE_SIZE * (1 << sz);
555
        pspartan_dev.video_base = virt_to_bus(pspartan_dev.video_vbase);
556
 
557
        for (page = virt_to_page(pspartan_dev.video_vbase); page <= virt_to_page(pspartan_dev.video_vbase + pspartan_dev.video_size - 1); page++)
558
                mem_map_reserve(page);
559
 
560
        printk(KERN_INFO "spartan: framebuffer at 0x%lx (phy 0x%lx), mapped to 0x%p, size %dk\n",
561
               pspartan_dev.video_base, virt_to_phys(pspartan_dev.video_vbase), pspartan_dev.video_vbase, pspartan_dev.video_size/1024);
562
#endif
563
 
564
        result = register_chrdev(REQUESTED_MAJOR, "spartan", &spartan_fops) ;
565
        if (result < 0)
566
        {
567
                printk(KERN_WARNING "spartan: can't get major number %d\n",REQUESTED_MAJOR) ;
568
                return result ;
569
        }
570
 
571
        printk("<1> Major number for spartan is %d \n", result );
572
        pspartan_dev.major = result ;
573
 
574
        return 0 ;
575
}
576
 
577
// celanup - unregister device
578
void cleanup_module(void)
579
{
580
        int result ;
581
        int size, sz;
582
 
583
#ifdef __VGA__
584
        for (sz = 0, size = PAGE_SIZE; size < VIDEO_SZ; sz++, size <<= 1);
585
        free_pages(pspartan_dev.video_vbase, sz);
586
#endif
587
        result = unregister_chrdev(pspartan_dev.major, "spartan") ;
588
        if (result < 0)
589
        {
590
                printk("<1> spartan device with major number %d unregistration failed \n", pspartan_dev.major);
591
                return ;
592
        }
593
        else
594
        {
595
                printk("<1> spartan device with major number %d unregistered succesfully \n", pspartan_dev.major);
596
                return ;
597
        }
598
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.