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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [hotplug/] [pci_hotplug_core.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * PCI HotPlug Controller Core
3
 *
4
 * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
5
 * Copyright (C) 2001-2002 IBM Corp.
6
 *
7
 * All rights reserved.
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or (at
12
 * your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17
 * NON INFRINGEMENT.  See the GNU General Public License for more
18
 * details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 * Send feedback to <greg@kroah.com>
25
 *
26
 * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
27
 *
28
 */
29
 
30
#include <linux/config.h>
31
#include <linux/module.h>
32
#include <linux/kernel.h>
33
#include <linux/types.h>
34
#include <linux/list.h>
35
#include <linux/pagemap.h>
36
#include <linux/slab.h>
37
#include <linux/smp_lock.h>
38
#include <linux/init.h>
39
#include <linux/pci.h>
40
#include <linux/dnotify.h>
41
#include <linux/proc_fs.h>
42
#include <asm/uaccess.h>
43
#include "pci_hotplug.h"
44
 
45
 
46
#if !defined(CONFIG_HOTPLUG_PCI_MODULE)
47
        #define MY_NAME "pci_hotplug"
48
#else
49
        #define MY_NAME THIS_MODULE->name
50
#endif
51
 
52
#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
53
#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
54
#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
55
#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
56
 
57
 
58
/* local variables */
59
static int debug;
60
 
61
#define DRIVER_VERSION  "0.5"
62
#define DRIVER_AUTHOR   "Greg Kroah-Hartman <greg@kroah.com>"
63
#define DRIVER_DESC     "PCI Hot Plug PCI Core"
64
 
65
 
66
//////////////////////////////////////////////////////////////////
67
 
68
/* Random magic number */
69
#define PCIHPFS_MAGIC 0x52454541
70
 
71
struct hotplug_slot_core {
72
        struct dentry   *dir_dentry;
73
        struct dentry   *power_dentry;
74
        struct dentry   *attention_dentry;
75
        struct dentry   *latch_dentry;
76
        struct dentry   *adapter_dentry;
77
        struct dentry   *test_dentry;
78
        struct dentry   *max_bus_speed_dentry;
79
        struct dentry   *cur_bus_speed_dentry;
80
};
81
 
82
static struct super_operations pcihpfs_ops;
83
static struct file_operations default_file_operations;
84
static struct inode_operations pcihpfs_dir_inode_operations;
85
static struct vfsmount *pcihpfs_mount;  /* one of the mounts of our fs for reference counting */
86
static int pcihpfs_mount_count;         /* times we have mounted our fs */
87
static spinlock_t mount_lock;           /* protects our mount_count */
88
static spinlock_t list_lock;
89
 
90
LIST_HEAD(pci_hotplug_slot_list);
91
 
92
/* these strings match up with the values in pci_bus_speed */
93
static char *pci_bus_speed_strings[] = {
94
        "33 MHz PCI",           /* 0x00 */
95
        "66 MHz PCI",           /* 0x01 */
96
        "66 MHz PCIX",          /* 0x02 */
97
        "100 MHz PCIX",         /* 0x03 */
98
        "133 MHz PCIX",         /* 0x04 */
99
        NULL,                   /* 0x05 */
100
        NULL,                   /* 0x06 */
101
        NULL,                   /* 0x07 */
102
        NULL,                   /* 0x08 */
103
        "66 MHz PCIX 266",      /* 0x09 */
104
        "100 MHz PCIX 266",     /* 0x0a */
105
        "133 MHz PCIX 266",     /* 0x0b */
106
        NULL,                   /* 0x0c */
107
        NULL,                   /* 0x0d */
108
        NULL,                   /* 0x0e */
109
        NULL,                   /* 0x0f */
110
        NULL,                   /* 0x10 */
111
        "66 MHz PCIX 533",      /* 0x11 */
112
        "100 MHz PCIX 533",     /* 0x12 */
113
        "133 MHz PCIX 533",     /* 0x13 */
114
};
115
 
116
static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf)
117
{
118
        buf->f_type = PCIHPFS_MAGIC;
119
        buf->f_bsize = PAGE_CACHE_SIZE;
120
        buf->f_namelen = 255;
121
        return 0;
122
}
123
 
124
static struct dentry *pcihpfs_lookup (struct inode *dir, struct dentry *dentry)
125
{
126
        d_add(dentry, NULL);
127
        return NULL;
128
}
129
 
130
#ifdef CONFIG_PROC_FS           
131
extern struct proc_dir_entry *proc_bus_pci_dir;
132
static struct proc_dir_entry *slotdir = NULL;
133
static const char *slotdir_name = "slots";
134
#endif
135
 
136
static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev)
137
{
138
        struct inode *inode = new_inode(sb);
139
 
140
        if (inode) {
141
                inode->i_mode = mode;
142
                inode->i_uid = current->fsuid;
143
                inode->i_gid = current->fsgid;
144
                inode->i_blksize = PAGE_CACHE_SIZE;
145
                inode->i_blocks = 0;
146
                inode->i_rdev = NODEV;
147
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
148
                switch (mode & S_IFMT) {
149
                default:
150
                        init_special_inode(inode, mode, dev);
151
                        break;
152
                case S_IFREG:
153
                        inode->i_fop = &default_file_operations;
154
                        break;
155
                case S_IFDIR:
156
                        inode->i_op = &pcihpfs_dir_inode_operations;
157
                        inode->i_fop = &dcache_dir_ops;
158
                        break;
159
                }
160
        }
161
        return inode;
162
}
163
 
164
static int pcihpfs_mknod (struct inode *dir, struct dentry *dentry, int mode, int dev)
165
{
166
        struct inode *inode = pcihpfs_get_inode(dir->i_sb, mode, dev);
167
        int error = -ENOSPC;
168
 
169
        if (inode) {
170
                d_instantiate(dentry, inode);
171
                dget(dentry);
172
                error = 0;
173
        }
174
        return error;
175
}
176
 
177
static int pcihpfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
178
{
179
        return pcihpfs_mknod (dir, dentry, mode | S_IFDIR, 0);
180
}
181
 
182
static int pcihpfs_create (struct inode *dir, struct dentry *dentry, int mode)
183
{
184
        return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0);
185
}
186
 
187
static inline int pcihpfs_positive (struct dentry *dentry)
188
{
189
        return dentry->d_inode && !d_unhashed(dentry);
190
}
191
 
192
static int pcihpfs_empty (struct dentry *dentry)
193
{
194
        struct list_head *list;
195
 
196
        spin_lock(&dcache_lock);
197
 
198
        list_for_each(list, &dentry->d_subdirs) {
199
                struct dentry *de = list_entry(list, struct dentry, d_child);
200
                if (pcihpfs_positive(de)) {
201
                        spin_unlock(&dcache_lock);
202
                        return 0;
203
                }
204
        }
205
 
206
        spin_unlock(&dcache_lock);
207
        return 1;
208
}
209
 
210
static int pcihpfs_unlink (struct inode *dir, struct dentry *dentry)
211
{
212
        int error = -ENOTEMPTY;
213
 
214
        if (pcihpfs_empty(dentry)) {
215
                struct inode *inode = dentry->d_inode;
216
 
217
                inode->i_nlink--;
218
                dput(dentry);
219
                error = 0;
220
        }
221
        return error;
222
}
223
 
224
#define pcihpfs_rmdir pcihpfs_unlink
225
 
226
/* default file operations */
227
static ssize_t default_read_file (struct file *file, char *buf, size_t count, loff_t *ppos)
228
{
229
        dbg ("\n");
230
        return 0;
231
}
232
 
233
static ssize_t default_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos)
234
{
235
        dbg ("\n");
236
        return count;
237
}
238
 
239
static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
240
{
241
        loff_t retval = -EINVAL;
242
 
243
        switch(orig) {
244
        case 0:
245
                if (offset > 0) {
246
                        file->f_pos = offset;
247
                        retval = file->f_pos;
248
                }
249
                break;
250
        case 1:
251
                if ((offset + file->f_pos) > 0) {
252
                        file->f_pos += offset;
253
                        retval = file->f_pos;
254
                }
255
                break;
256
        default:
257
                break;
258
        }
259
        return retval;
260
}
261
 
262
static int default_open (struct inode *inode, struct file *filp)
263
{
264
        if (inode->u.generic_ip)
265
                filp->private_data = inode->u.generic_ip;
266
 
267
        return 0;
268
}
269
 
270
static struct file_operations default_file_operations = {
271
        read:           default_read_file,
272
        write:          default_write_file,
273
        open:           default_open,
274
        llseek:         default_file_lseek,
275
};
276
 
277
/* file ops for the "power" files */
278
static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
279
static ssize_t power_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
280
static struct file_operations power_file_operations = {
281
        read:           power_read_file,
282
        write:          power_write_file,
283
        open:           default_open,
284
        llseek:         default_file_lseek,
285
};
286
 
287
/* file ops for the "attention" files */
288
static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
289
static ssize_t attention_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
290
static struct file_operations attention_file_operations = {
291
        read:           attention_read_file,
292
        write:          attention_write_file,
293
        open:           default_open,
294
        llseek:         default_file_lseek,
295
};
296
 
297
/* file ops for the "latch" files */
298
static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
299
static struct file_operations latch_file_operations = {
300
        read:           latch_read_file,
301
        write:          default_write_file,
302
        open:           default_open,
303
        llseek:         default_file_lseek,
304
};
305
 
306
/* file ops for the "presence" files */
307
static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
308
static struct file_operations presence_file_operations = {
309
        read:           presence_read_file,
310
        write:          default_write_file,
311
        open:           default_open,
312
        llseek:         default_file_lseek,
313
};
314
 
315
/* file ops for the "max bus speed" files */
316
static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
317
static struct file_operations max_bus_speed_file_operations = {
318
        read:           max_bus_speed_read_file,
319
        write:          default_write_file,
320
        open:           default_open,
321
        llseek:         default_file_lseek,
322
};
323
 
324
/* file ops for the "current bus speed" files */
325
static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
326
static struct file_operations cur_bus_speed_file_operations = {
327
        read:           cur_bus_speed_read_file,
328
        write:          default_write_file,
329
        open:           default_open,
330
        llseek:         default_file_lseek,
331
};
332
 
333
/* file ops for the "test" files */
334
static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
335
static struct file_operations test_file_operations = {
336
        read:           default_read_file,
337
        write:          test_write_file,
338
        open:           default_open,
339
        llseek:         default_file_lseek,
340
};
341
 
342
static struct inode_operations pcihpfs_dir_inode_operations = {
343
        create:         pcihpfs_create,
344
        lookup:         pcihpfs_lookup,
345
        unlink:         pcihpfs_unlink,
346
        mkdir:          pcihpfs_mkdir,
347
        rmdir:          pcihpfs_rmdir,
348
        mknod:          pcihpfs_mknod,
349
};
350
 
351
static struct super_operations pcihpfs_ops = {
352
        statfs:         pcihpfs_statfs,
353
        put_inode:      force_delete,
354
};
355
 
356
static struct super_block *pcihpfs_read_super (struct super_block *sb, void *data, int silent)
357
{
358
        struct inode *inode;
359
        struct dentry *root;
360
 
361
        sb->s_blocksize = PAGE_CACHE_SIZE;
362
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
363
        sb->s_magic = PCIHPFS_MAGIC;
364
        sb->s_op = &pcihpfs_ops;
365
        inode = pcihpfs_get_inode(sb, S_IFDIR | 0755, 0);
366
 
367
        if (!inode) {
368
                dbg("%s: could not get inode!\n",__FUNCTION__);
369
                return NULL;
370
        }
371
 
372
        root = d_alloc_root(inode);
373
        if (!root) {
374
                dbg("%s: could not get root dentry!\n",__FUNCTION__);
375
                iput(inode);
376
                return NULL;
377
        }
378
        sb->s_root = root;
379
        return sb;
380
}
381
 
382
static DECLARE_FSTYPE(pcihpfs_fs_type, "pcihpfs", pcihpfs_read_super, FS_SINGLE | FS_LITTER);
383
 
384
static int get_mount (void)
385
{
386
        struct vfsmount *mnt;
387
 
388
        spin_lock (&mount_lock);
389
        if (pcihpfs_mount) {
390
                mntget(pcihpfs_mount);
391
                ++pcihpfs_mount_count;
392
                spin_unlock (&mount_lock);
393
                goto go_ahead;
394
        }
395
 
396
        spin_unlock (&mount_lock);
397
        mnt = kern_mount (&pcihpfs_fs_type);
398
        if (IS_ERR(mnt)) {
399
                err ("could not mount the fs...erroring out!\n");
400
                return -ENODEV;
401
        }
402
        spin_lock (&mount_lock);
403
        if (!pcihpfs_mount) {
404
                pcihpfs_mount = mnt;
405
                ++pcihpfs_mount_count;
406
                spin_unlock (&mount_lock);
407
                goto go_ahead;
408
        }
409
        mntget(pcihpfs_mount);
410
        ++pcihpfs_mount_count;
411
        spin_unlock (&mount_lock);
412
        mntput(mnt);
413
 
414
go_ahead:
415
        dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count);
416
        return 0;
417
}
418
 
419
static void remove_mount (void)
420
{
421
        struct vfsmount *mnt;
422
 
423
        spin_lock (&mount_lock);
424
        mnt = pcihpfs_mount;
425
        --pcihpfs_mount_count;
426
        if (!pcihpfs_mount_count)
427
                pcihpfs_mount = NULL;
428
 
429
        spin_unlock (&mount_lock);
430
        mntput(mnt);
431
        dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count);
432
}
433
 
434
 
435
/**
436
 * pcihpfs_create_by_name - create a file, given a name
437
 * @name:       name of file
438
 * @mode:       type of file
439
 * @parent:     dentry of directory to create it in
440
 * @dentry:     resulting dentry of file
441
 *
442
 * There is a bit of overhead in creating a file - basically, we
443
 * have to hash the name of the file, then look it up. This will
444
 * prevent files of the same name.
445
 * We then call the proper vfs_ function to take care of all the
446
 * file creation details.
447
 * This function handles both regular files and directories.
448
 */
449
static int pcihpfs_create_by_name (const char *name, mode_t mode,
450
                                   struct dentry *parent, struct dentry **dentry)
451
{
452
        struct dentry *d = NULL;
453
        struct qstr qstr;
454
        int error;
455
 
456
        /* If the parent is not specified, we create it in the root.
457
         * We need the root dentry to do this, which is in the super
458
         * block. A pointer to that is in the struct vfsmount that we
459
         * have around.
460
         */
461
        if (!parent ) {
462
                if (pcihpfs_mount && pcihpfs_mount->mnt_sb) {
463
                        parent = pcihpfs_mount->mnt_sb->s_root;
464
                }
465
        }
466
 
467
        if (!parent) {
468
                dbg("Ah! can not find a parent!\n");
469
                return -EINVAL;
470
        }
471
 
472
        *dentry = NULL;
473
        qstr.name = name;
474
        qstr.len = strlen(name);
475
        qstr.hash = full_name_hash(name,qstr.len);
476
 
477
        parent = dget(parent);
478
 
479
        down(&parent->d_inode->i_sem);
480
 
481
        d = lookup_hash(&qstr,parent);
482
 
483
        error = PTR_ERR(d);
484
        if (!IS_ERR(d)) {
485
                switch(mode & S_IFMT) {
486
                case 0:
487
                case S_IFREG:
488
                        error = vfs_create(parent->d_inode,d,mode);
489
                        break;
490
                case S_IFDIR:
491
                        error = vfs_mkdir(parent->d_inode,d,mode);
492
                        break;
493
                default:
494
                        err("cannot create special files\n");
495
                }
496
                *dentry = d;
497
        }
498
        up(&parent->d_inode->i_sem);
499
 
500
        dput(parent);
501
        return error;
502
}
503
 
504
static struct dentry *fs_create_file (const char *name, mode_t mode,
505
                                      struct dentry *parent, void *data,
506
                                      struct file_operations *fops)
507
{
508
        struct dentry *dentry;
509
        int error;
510
 
511
        dbg("creating file '%s'\n",name);
512
 
513
        error = pcihpfs_create_by_name(name,mode,parent,&dentry);
514
        if (error) {
515
                dentry = NULL;
516
        } else {
517
                if (dentry->d_inode) {
518
                        if (data)
519
                                dentry->d_inode->u.generic_ip = data;
520
                        if (fops)
521
                        dentry->d_inode->i_fop = fops;
522
                }
523
        }
524
 
525
        return dentry;
526
}
527
 
528
static void fs_remove_file (struct dentry *dentry)
529
{
530
        struct dentry *parent = dentry->d_parent;
531
 
532
        if (!parent || !parent->d_inode)
533
                return;
534
 
535
        down(&parent->d_inode->i_sem);
536
        if (pcihpfs_positive(dentry)) {
537
                if (dentry->d_inode) {
538
                        if (S_ISDIR(dentry->d_inode->i_mode))
539
                                vfs_rmdir(parent->d_inode,dentry);
540
                        else
541
                                vfs_unlink(parent->d_inode,dentry);
542
                }
543
 
544
                dput(dentry);
545
        }
546
        up(&parent->d_inode->i_sem);
547
}
548
 
549
#define GET_STATUS(name,type)   \
550
static int get_##name (struct hotplug_slot *slot, type *value)          \
551
{                                                                       \
552
        struct hotplug_slot_ops *ops = slot->ops;                       \
553
        int retval = 0;                                                  \
554
        if (ops->owner)                                                 \
555
                __MOD_INC_USE_COUNT(ops->owner);                        \
556
        if (ops->get_##name)                                            \
557
                retval = ops->get_##name (slot, value);                 \
558
        else                                                            \
559
                *value = slot->info->name;                              \
560
        if (ops->owner)                                                 \
561
                __MOD_DEC_USE_COUNT(ops->owner);                        \
562
        return retval;                                                  \
563
}
564
 
565
GET_STATUS(power_status, u8)
566
GET_STATUS(attention_status, u8)
567
GET_STATUS(latch_status, u8)
568
GET_STATUS(adapter_status, u8)
569
GET_STATUS(max_bus_speed, enum pci_bus_speed)
570
GET_STATUS(cur_bus_speed, enum pci_bus_speed)
571
 
572
static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
573
{
574
        struct hotplug_slot *slot = file->private_data;
575
        unsigned char *page;
576
        int retval;
577
        int len;
578
        u8 value;
579
 
580
        dbg(" count = %d, offset = %lld\n", count, *offset);
581
 
582
        if (*offset < 0)
583
                return -EINVAL;
584
        if (count == 0 || count > 16384)
585
                return 0;
586
        if (*offset != 0)
587
                return 0;
588
 
589
        if (slot == NULL) {
590
                dbg("slot == NULL???\n");
591
                return -ENODEV;
592
        }
593
 
594
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
595
        if (!page)
596
                return -ENOMEM;
597
 
598
        retval = get_power_status (slot, &value);
599
        if (retval)
600
                goto exit;
601
        len = sprintf (page, "%d\n", value);
602
 
603
        if (copy_to_user (buf, page, len)) {
604
                retval = -EFAULT;
605
                goto exit;
606
        }
607
        *offset += len;
608
        retval = len;
609
 
610
exit:
611
        free_page((unsigned long)page);
612
        return retval;
613
}
614
 
615
static ssize_t power_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
616
{
617
        struct hotplug_slot *slot = file->private_data;
618
        char *buff;
619
        unsigned long lpower;
620
        u8 power;
621
        int retval = 0;
622
 
623
        if (*offset < 0)
624
                return -EINVAL;
625
        if (count == 0 || count > 16384)
626
                return 0;
627
        if (*offset != 0)
628
                return 0;
629
 
630
        if (slot == NULL) {
631
                dbg("slot == NULL???\n");
632
                return -ENODEV;
633
        }
634
 
635
        buff = kmalloc (count + 1, GFP_KERNEL);
636
        if (!buff)
637
                return -ENOMEM;
638
        memset (buff, 0x00, count + 1);
639
 
640
        if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
641
                retval = -EFAULT;
642
                goto exit;
643
        }
644
 
645
        lpower = simple_strtoul (buff, NULL, 10);
646
        power = (u8)(lpower & 0xff);
647
        dbg ("power = %d\n", power);
648
 
649
        switch (power) {
650
                case 0:
651
                        if (!slot->ops->disable_slot)
652
                                break;
653
                        if (slot->ops->owner)
654
                                __MOD_INC_USE_COUNT(slot->ops->owner);
655
                        retval = slot->ops->disable_slot(slot);
656
                        if (slot->ops->owner)
657
                                __MOD_DEC_USE_COUNT(slot->ops->owner);
658
                        break;
659
 
660
                case 1:
661
                        if (!slot->ops->enable_slot)
662
                                break;
663
                        if (slot->ops->owner)
664
                                __MOD_INC_USE_COUNT(slot->ops->owner);
665
                        retval = slot->ops->enable_slot(slot);
666
                        if (slot->ops->owner)
667
                                __MOD_DEC_USE_COUNT(slot->ops->owner);
668
                        break;
669
 
670
                default:
671
                        err ("Illegal value specified for power\n");
672
                        retval = -EINVAL;
673
        }
674
 
675
exit:
676
        kfree (buff);
677
 
678
        if (retval)
679
                return retval;
680
        return count;
681
}
682
 
683
static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
684
{
685
        struct hotplug_slot *slot = file->private_data;
686
        unsigned char *page;
687
        int retval;
688
        int len;
689
        u8 value;
690
 
691
        dbg("count = %d, offset = %lld\n", count, *offset);
692
 
693
        if (*offset < 0)
694
                return -EINVAL;
695
        if (count == 0 || count > 16384)
696
                return 0;
697
        if (*offset != 0)
698
                return 0;
699
 
700
        if (slot == NULL) {
701
                dbg("slot == NULL???\n");
702
                return -ENODEV;
703
        }
704
 
705
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
706
        if (!page)
707
                return -ENOMEM;
708
 
709
        retval = get_attention_status (slot, &value);
710
        if (retval)
711
                goto exit;
712
        len = sprintf (page, "%d\n", value);
713
 
714
        if (copy_to_user (buf, page, len)) {
715
                retval = -EFAULT;
716
                goto exit;
717
        }
718
        *offset += len;
719
        retval = len;
720
 
721
exit:
722
        free_page((unsigned long)page);
723
        return retval;
724
}
725
 
726
static ssize_t attention_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
727
{
728
        struct hotplug_slot *slot = file->private_data;
729
        char *buff;
730
        unsigned long lattention;
731
        u8 attention;
732
        int retval = 0;
733
 
734
        if (*offset < 0)
735
                return -EINVAL;
736
        if (count == 0 || count > 16384)
737
                return 0;
738
        if (*offset != 0)
739
                return 0;
740
 
741
        if (slot == NULL) {
742
                dbg("slot == NULL???\n");
743
                return -ENODEV;
744
        }
745
 
746
        buff = kmalloc (count + 1, GFP_KERNEL);
747
        if (!buff)
748
                return -ENOMEM;
749
        memset (buff, 0x00, count + 1);
750
 
751
        if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
752
                retval = -EFAULT;
753
                goto exit;
754
        }
755
 
756
        lattention = simple_strtoul (buff, NULL, 10);
757
        attention = (u8)(lattention & 0xff);
758
        dbg (" - attention = %d\n", attention);
759
 
760
        if (slot->ops->set_attention_status) {
761
                if (slot->ops->owner)
762
                        __MOD_INC_USE_COUNT(slot->ops->owner);
763
                retval = slot->ops->set_attention_status(slot, attention);
764
                if (slot->ops->owner)
765
                        __MOD_DEC_USE_COUNT(slot->ops->owner);
766
        }
767
 
768
exit:
769
        kfree (buff);
770
 
771
        if (retval)
772
                return retval;
773
        return count;
774
}
775
 
776
static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
777
{
778
        struct hotplug_slot *slot = file->private_data;
779
        unsigned char *page;
780
        int retval;
781
        int len;
782
        u8 value;
783
 
784
        dbg("count = %d, offset = %lld\n", count, *offset);
785
 
786
        if (*offset < 0)
787
                return -EINVAL;
788
        if (count <= 0)
789
                return 0;
790
        if (*offset != 0)
791
                return 0;
792
 
793
        if (slot == NULL) {
794
                dbg("slot == NULL???\n");
795
                return -ENODEV;
796
        }
797
 
798
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
799
        if (!page)
800
                return -ENOMEM;
801
 
802
        retval = get_latch_status (slot, &value);
803
        if (retval)
804
                goto exit;
805
        len = sprintf (page, "%d\n", value);
806
 
807
        if (copy_to_user (buf, page, len)) {
808
                retval = -EFAULT;
809
                goto exit;
810
        }
811
        *offset += len;
812
        retval = len;
813
 
814
exit:
815
        free_page((unsigned long)page);
816
        return retval;
817
}
818
 
819
static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
820
{
821
        struct hotplug_slot *slot = file->private_data;
822
        unsigned char *page;
823
        int retval;
824
        int len;
825
        u8 value;
826
 
827
        dbg("count = %d, offset = %lld\n", count, *offset);
828
 
829
        if (*offset < 0)
830
                return -EINVAL;
831
        if (count <= 0)
832
                return 0;
833
        if (*offset != 0)
834
                return 0;
835
 
836
        if (slot == NULL) {
837
                dbg("slot == NULL???\n");
838
                return -ENODEV;
839
        }
840
 
841
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
842
        if (!page)
843
                return -ENOMEM;
844
 
845
        retval = get_adapter_status (slot, &value);
846
        if (retval)
847
                goto exit;
848
        len = sprintf (page, "%d\n", value);
849
 
850
        if (copy_to_user (buf, page, len)) {
851
                retval = -EFAULT;
852
                goto exit;
853
        }
854
        *offset += len;
855
        retval = len;
856
 
857
exit:
858
        free_page((unsigned long)page);
859
        return retval;
860
}
861
 
862
static char *unknown_speed = "Unknown bus speed";
863
 
864
static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
865
{
866
        struct hotplug_slot *slot = file->private_data;
867
        unsigned char *page;
868
        char *speed_string;
869
        int retval;
870
        int len = 0;
871
        enum pci_bus_speed value;
872
 
873
        dbg ("count = %d, offset = %lld\n", count, *offset);
874
 
875
        if (*offset < 0)
876
                return -EINVAL;
877
        if (count <= 0)
878
                return 0;
879
        if (*offset != 0)
880
                return 0;
881
 
882
        if (slot == NULL) {
883
                dbg("slot == NULL???\n");
884
                return -ENODEV;
885
        }
886
 
887
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
888
        if (!page)
889
                return -ENOMEM;
890
 
891
        retval = get_max_bus_speed (slot, &value);
892
        if (retval)
893
                goto exit;
894
 
895
        if (value == PCI_SPEED_UNKNOWN)
896
                speed_string = unknown_speed;
897
        else
898
                speed_string = pci_bus_speed_strings[value];
899
 
900
        len = sprintf (page, "%s\n", speed_string);
901
 
902
        if (copy_to_user (buf, page, len)) {
903
                retval = -EFAULT;
904
                goto exit;
905
        }
906
        *offset += len;
907
        retval = len;
908
 
909
exit:
910
        free_page((unsigned long)page);
911
        return retval;
912
}
913
 
914
static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
915
{
916
        struct hotplug_slot *slot = file->private_data;
917
        unsigned char *page;
918
        char *speed_string;
919
        int retval;
920
        int len = 0;
921
        enum pci_bus_speed value;
922
 
923
        dbg ("count = %d, offset = %lld\n", count, *offset);
924
 
925
        if (*offset < 0)
926
                return -EINVAL;
927
        if (count <= 0)
928
                return 0;
929
        if (*offset != 0)
930
                return 0;
931
 
932
        if (slot == NULL) {
933
                dbg("slot == NULL???\n");
934
                return -ENODEV;
935
        }
936
 
937
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
938
        if (!page)
939
                return -ENOMEM;
940
 
941
        retval = get_cur_bus_speed (slot, &value);
942
        if (retval)
943
                goto exit;
944
 
945
        if (value == PCI_SPEED_UNKNOWN)
946
                speed_string = unknown_speed;
947
        else
948
                speed_string = pci_bus_speed_strings[value];
949
 
950
        len = sprintf (page, "%s\n", speed_string);
951
 
952
        if (copy_to_user (buf, page, len)) {
953
                retval = -EFAULT;
954
                goto exit;
955
        }
956
        *offset += len;
957
        retval = len;
958
 
959
exit:
960
        free_page((unsigned long)page);
961
        return retval;
962
}
963
 
964
static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
965
{
966
        struct hotplug_slot *slot = file->private_data;
967
        char *buff;
968
        unsigned long ltest;
969
        u32 test;
970
        int retval = 0;
971
 
972
        if (*offset < 0)
973
                return -EINVAL;
974
        if (count == 0 || count > 16384)
975
                return 0;
976
        if (*offset != 0)
977
                return 0;
978
 
979
        if (slot == NULL) {
980
                dbg("slot == NULL???\n");
981
                return -ENODEV;
982
        }
983
 
984
        buff = kmalloc (count + 1, GFP_KERNEL);
985
        if (!buff)
986
                return -ENOMEM;
987
        memset (buff, 0x00, count + 1);
988
 
989
        if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
990
                retval = -EFAULT;
991
                goto exit;
992
        }
993
 
994
        ltest = simple_strtoul (buff, NULL, 10);
995
        test = (u32)(ltest & 0xffffffff);
996
        dbg ("test = %d\n", test);
997
 
998
        if (slot->ops->hardware_test) {
999
                if (slot->ops->owner)
1000
                        __MOD_INC_USE_COUNT(slot->ops->owner);
1001
                retval = slot->ops->hardware_test(slot, test);
1002
                if (slot->ops->owner)
1003
                        __MOD_DEC_USE_COUNT(slot->ops->owner);
1004
        }
1005
 
1006
exit:
1007
        kfree (buff);
1008
 
1009
        if (retval)
1010
                return retval;
1011
        return count;
1012
}
1013
 
1014
static int fs_add_slot (struct hotplug_slot *slot)
1015
{
1016
        struct hotplug_slot_core *core = slot->core_priv;
1017
        int result;
1018
 
1019
        result = get_mount();
1020
        if (result)
1021
                return result;
1022
 
1023
        core->dir_dentry = fs_create_file (slot->name,
1024
                                           S_IFDIR | S_IXUGO | S_IRUGO,
1025
                                           NULL, NULL, NULL);
1026
        if (core->dir_dentry != NULL) {
1027
                if ((slot->ops->enable_slot) ||
1028
                    (slot->ops->disable_slot) ||
1029
                    (slot->ops->get_power_status))
1030
                        core->power_dentry =
1031
                                fs_create_file ("power",
1032
                                                S_IFREG | S_IRUGO | S_IWUSR,
1033
                                                core->dir_dentry, slot,
1034
                                                &power_file_operations);
1035
 
1036
                if ((slot->ops->set_attention_status) ||
1037
                    (slot->ops->get_attention_status))
1038
                        core->attention_dentry =
1039
                                fs_create_file ("attention",
1040
                                                S_IFREG | S_IRUGO | S_IWUSR,
1041
                                                core->dir_dentry, slot,
1042
                                                &attention_file_operations);
1043
 
1044
                if (slot->ops->get_latch_status)
1045
                        core->latch_dentry =
1046
                                fs_create_file ("latch",
1047
                                                S_IFREG | S_IRUGO,
1048
                                                core->dir_dentry, slot,
1049
                                                &latch_file_operations);
1050
 
1051
                if (slot->ops->get_adapter_status)
1052
                        core->adapter_dentry =
1053
                                fs_create_file ("adapter",
1054
                                                S_IFREG | S_IRUGO,
1055
                                                core->dir_dentry, slot,
1056
                                                &presence_file_operations);
1057
 
1058
                if (slot->ops->get_max_bus_speed)
1059
                        core->max_bus_speed_dentry =
1060
                                fs_create_file ("max_bus_speed",
1061
                                                S_IFREG | S_IRUGO,
1062
                                                core->dir_dentry, slot,
1063
                                                &max_bus_speed_file_operations);
1064
 
1065
                if (slot->ops->get_cur_bus_speed)
1066
                        core->cur_bus_speed_dentry =
1067
                                fs_create_file ("cur_bus_speed",
1068
                                                S_IFREG | S_IRUGO,
1069
                                                core->dir_dentry, slot,
1070
                                                &cur_bus_speed_file_operations);
1071
 
1072
                if (slot->ops->hardware_test)
1073
                        core->test_dentry =
1074
                                fs_create_file ("test",
1075
                                                S_IFREG | S_IRUGO | S_IWUSR,
1076
                                                core->dir_dentry, slot,
1077
                                                &test_file_operations);
1078
        }
1079
        return 0;
1080
}
1081
 
1082
static void fs_remove_slot (struct hotplug_slot *slot)
1083
{
1084
        struct hotplug_slot_core *core = slot->core_priv;
1085
 
1086
        if (core->dir_dentry) {
1087
                if (core->power_dentry)
1088
                        fs_remove_file (core->power_dentry);
1089
                if (core->attention_dentry)
1090
                        fs_remove_file (core->attention_dentry);
1091
                if (core->latch_dentry)
1092
                        fs_remove_file (core->latch_dentry);
1093
                if (core->adapter_dentry)
1094
                        fs_remove_file (core->adapter_dentry);
1095
                if (core->max_bus_speed_dentry)
1096
                        fs_remove_file (core->max_bus_speed_dentry);
1097
                if (core->cur_bus_speed_dentry)
1098
                        fs_remove_file (core->cur_bus_speed_dentry);
1099
                if (core->test_dentry)
1100
                        fs_remove_file (core->test_dentry);
1101
                fs_remove_file (core->dir_dentry);
1102
        }
1103
 
1104
        remove_mount();
1105
}
1106
 
1107
static struct hotplug_slot *get_slot_from_name (const char *name)
1108
{
1109
        struct hotplug_slot *slot;
1110
        struct list_head *tmp;
1111
 
1112
        list_for_each (tmp, &pci_hotplug_slot_list) {
1113
                slot = list_entry (tmp, struct hotplug_slot, slot_list);
1114
                if (strcmp(slot->name, name) == 0)
1115
                        return slot;
1116
        }
1117
        return NULL;
1118
}
1119
 
1120
/**
1121
 * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
1122
 * @slot: pointer to the &struct hotplug_slot to register
1123
 *
1124
 * Registers a hotplug slot with the pci hotplug subsystem, which will allow
1125
 * userspace interaction to the slot.
1126
 *
1127
 * Returns 0 if successful, anything else for an error.
1128
 */
1129
int pci_hp_register (struct hotplug_slot *slot)
1130
{
1131
        struct hotplug_slot_core *core;
1132
        int result;
1133
 
1134
        if (slot == NULL)
1135
                return -ENODEV;
1136
        if ((slot->info == NULL) || (slot->ops == NULL))
1137
                return -EINVAL;
1138
 
1139
        core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL);
1140
        if (!core)
1141
                return -ENOMEM;
1142
 
1143
        /* make sure we have not already registered this slot */
1144
        spin_lock (&list_lock);
1145
        if (get_slot_from_name (slot->name) != NULL) {
1146
                spin_unlock (&list_lock);
1147
                kfree (core);
1148
                return -EEXIST;
1149
        }
1150
 
1151
        memset (core, 0, sizeof (struct hotplug_slot_core));
1152
        slot->core_priv = core;
1153
 
1154
        list_add (&slot->slot_list, &pci_hotplug_slot_list);
1155
        spin_unlock (&list_lock);
1156
 
1157
        result = fs_add_slot (slot);
1158
        dbg ("Added slot %s to the list\n", slot->name);
1159
        return result;
1160
}
1161
 
1162
/**
1163
 * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
1164
 * @slot: pointer to the &struct hotplug_slot to deregister
1165
 *
1166
 * The @slot must have been registered with the pci hotplug subsystem
1167
 * previously with a call to pci_hp_register().
1168
 *
1169
 * Returns 0 if successful, anything else for an error.
1170
 */
1171
int pci_hp_deregister (struct hotplug_slot *slot)
1172
{
1173
        struct hotplug_slot *temp;
1174
 
1175
        if (slot == NULL)
1176
                return -ENODEV;
1177
 
1178
        /* make sure we have this slot in our list before trying to delete it */
1179
        spin_lock (&list_lock);
1180
        temp = get_slot_from_name (slot->name);
1181
        if (temp != slot) {
1182
                spin_unlock (&list_lock);
1183
                return -ENODEV;
1184
        }
1185
 
1186
        list_del (&slot->slot_list);
1187
        spin_unlock (&list_lock);
1188
 
1189
        fs_remove_slot (slot);
1190
        kfree(slot->core_priv);
1191
        dbg ("Removed slot %s from the list\n", slot->name);
1192
        return 0;
1193
}
1194
 
1195
static inline void update_dentry_inode_time (struct dentry *dentry)
1196
{
1197
        struct inode *inode = dentry->d_inode;
1198
        if (inode) {
1199
                inode->i_mtime = CURRENT_TIME;
1200
                dnotify_parent(dentry, DN_MODIFY);
1201
        }
1202
}
1203
 
1204
/**
1205
 * pci_hp_change_slot_info - changes the slot's information structure in the core
1206
 * @name: the name of the slot whose info has changed
1207
 * @info: pointer to the info copy into the slot's info structure
1208
 *
1209
 * A slot with @name must have been registered with the pci
1210
 * hotplug subsystem previously with a call to pci_hp_register().
1211
 *
1212
 * Returns 0 if successful, anything else for an error.
1213
 */
1214
int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info)
1215
{
1216
        struct hotplug_slot *temp;
1217
        struct hotplug_slot_core *core;
1218
 
1219
        if (info == NULL)
1220
                return -ENODEV;
1221
 
1222
        spin_lock (&list_lock);
1223
        temp = get_slot_from_name (name);
1224
        if (temp == NULL) {
1225
                spin_unlock (&list_lock);
1226
                return -ENODEV;
1227
        }
1228
 
1229
        /*
1230
         * check all fields in the info structure, and update timestamps
1231
         * for the files referring to the fields that have now changed.
1232
         */
1233
        core = temp->core_priv;
1234
        if ((core->power_dentry) &&
1235
            (temp->info->power_status != info->power_status))
1236
                update_dentry_inode_time (core->power_dentry);
1237
        if ((core->attention_dentry) &&
1238
            (temp->info->attention_status != info->attention_status))
1239
                update_dentry_inode_time (core->attention_dentry);
1240
        if ((core->latch_dentry) &&
1241
            (temp->info->latch_status != info->latch_status))
1242
                update_dentry_inode_time (core->latch_dentry);
1243
        if ((core->adapter_dentry) &&
1244
            (temp->info->adapter_status != info->adapter_status))
1245
                update_dentry_inode_time (core->adapter_dentry);
1246
        if ((core->cur_bus_speed_dentry) &&
1247
            (temp->info->cur_bus_speed != info->cur_bus_speed))
1248
                update_dentry_inode_time (core->cur_bus_speed_dentry);
1249
 
1250
        memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
1251
        spin_unlock (&list_lock);
1252
        return 0;
1253
}
1254
 
1255
static int __init pci_hotplug_init (void)
1256
{
1257
        int result;
1258
 
1259
        spin_lock_init(&mount_lock);
1260
        spin_lock_init(&list_lock);
1261
 
1262
        dbg("registering filesystem.\n");
1263
        result = register_filesystem(&pcihpfs_fs_type);
1264
        if (result) {
1265
                err("register_filesystem failed with %d\n", result);
1266
                goto exit;
1267
        }
1268
 
1269
#ifdef CONFIG_PROC_FS
1270
        /* create mount point for pcihpfs */
1271
        slotdir = proc_mkdir(slotdir_name, proc_bus_pci_dir);
1272
#endif
1273
 
1274
        info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
1275
 
1276
exit:
1277
        return result;
1278
}
1279
 
1280
static void __exit pci_hotplug_exit (void)
1281
{
1282
        unregister_filesystem(&pcihpfs_fs_type);
1283
 
1284
#ifdef CONFIG_PROC_FS
1285
        if (slotdir)
1286
                remove_proc_entry(slotdir_name, proc_bus_pci_dir);
1287
#endif
1288
}
1289
 
1290
module_init(pci_hotplug_init);
1291
module_exit(pci_hotplug_exit);
1292
 
1293
MODULE_AUTHOR(DRIVER_AUTHOR);
1294
MODULE_DESCRIPTION(DRIVER_DESC);
1295
MODULE_LICENSE("GPL");
1296
MODULE_PARM(debug, "i");
1297
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
1298
 
1299
EXPORT_SYMBOL_GPL(pci_hp_register);
1300
EXPORT_SYMBOL_GPL(pci_hp_deregister);
1301
EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
1302
 

powered by: WebSVN 2.1.0

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