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