special usb hub handling, IDE disks, and retries all over the place
[linux-2.4.git] / drivers / s390 / s390dyn.c
1 /*
2  *  arch/s390/kernel/s390dyn.c
3  *   S/390 dynamic device attachment
4  *
5  *  S390 version
6  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
8  */
9
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/smp_lock.h>
13
14 #include <asm/irq.h>
15 #include <asm/s390io.h>
16 #include <asm/s390dyn.h>
17
18 static struct list_head devreg_anchor = LIST_HEAD_INIT(devreg_anchor);
19 static spinlock_t  dyn_lock           = SPIN_LOCK_UNLOCKED;
20
21 static inline int s390_device_register_internal(devreg_t *drinfo)
22 {
23         struct list_head *p;
24
25         list_for_each(p, &devreg_anchor) {
26                 devreg_t *pdevreg = list_entry(p, devreg_t, list);
27                 
28                 if (pdevreg == drinfo)
29                         return -EINVAL;
30                 /*
31                  * We don't allow multiple drivers to register
32                  * for the same device number
33                  */
34                 if (pdevreg->ci.devno == drinfo->ci.devno &&
35                     (pdevreg->flag & DEVREG_TYPE_DEVNO) &&
36                     (drinfo->flag & DEVREG_TYPE_DEVNO))
37                         return -EBUSY;
38
39                 if (drinfo->flag == (DEVREG_TYPE_DEVCHARS | 
40                                      DEVREG_EXACT_MATCH) &&
41                     !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc,
42                             sizeof(devreg_hc_t))) 
43                         return -EBUSY;
44         }
45
46         /*
47          * no collision found, enqueue
48          */
49         list_add (&drinfo->list, &devreg_anchor);
50         
51         return 0;
52 }
53
54 int s390_device_register( devreg_t *drinfo )
55 {
56         unsigned long flags;
57         int ret;
58
59         if (drinfo == NULL ||
60             !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS)))
61                 return -EINVAL;
62
63         spin_lock_irqsave (&dyn_lock, flags);   
64         ret = s390_device_register_internal(drinfo);
65         spin_unlock_irqrestore( &dyn_lock, flags );     
66         
67         return ret;
68 }
69
70 static inline int s390_device_unregister_internal(devreg_t *dreg)
71 {
72         struct list_head *p;
73
74         list_for_each(p, &devreg_anchor) {
75                 devreg_t *pdevreg = list_entry(p, devreg_t, list);
76
77                 if (pdevreg == dreg) {
78                         list_del (&dreg->list);
79                         return 0;
80                 }
81         }
82         return -EINVAL;
83 }
84
85 int s390_device_unregister(devreg_t *dreg)
86 {
87         unsigned long  flags;
88         int ret;
89
90         if (dreg == NULL)
91                 return -EINVAL;
92
93         spin_lock_irqsave(&dyn_lock, flags);    
94         ret = s390_device_unregister_internal(dreg);
95         spin_unlock_irqrestore(&dyn_lock, flags);       
96         
97         return ret;
98 }
99
100 static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo)
101 {
102         struct list_head *p;
103         
104         list_for_each(p, &devreg_anchor) {
105                 devreg_t *pdevreg = list_entry(p, devreg_t, list);
106                 senseid_t *sid;
107                 int flag;
108
109                 flag = pdevreg->flag;
110                 sid = &ioinfo->senseid;
111                 if (flag & DEVREG_TYPE_DEVNO) {
112                         if (ioinfo->ui.flags.dval != 1 ||
113                             ioinfo->devno != pdevreg->ci.devno)
114                                 continue;
115                 } else if (flag & DEVREG_TYPE_DEVCHARS) {
116                         if ( (flag & DEVREG_MATCH_CU_TYPE) &&
117                              pdevreg->ci.hc.ctype != sid->cu_type )
118                                 continue;
119                         if ( (flag & DEVREG_MATCH_CU_MODEL) &&
120                              pdevreg->ci.hc.cmode != sid->cu_model )
121                                 continue;
122                         if ( (flag & DEVREG_MATCH_DEV_TYPE) &&
123                              pdevreg->ci.hc.dtype != sid->dev_type )
124                                 continue;
125                         if ( (flag & DEVREG_MATCH_DEV_MODEL) &&
126                              pdevreg->ci.hc.dmode != sid->dev_model )
127                                 continue;
128                 } else {
129                         continue;
130                 }
131                 
132                 return pdevreg;
133         }
134         return NULL;
135 }
136
137 devreg_t * s390_search_devreg( ioinfo_t *ioinfo )
138 {
139         unsigned long  flags;
140         devreg_t *pdevreg;
141
142         if (ioinfo == NULL)
143                 return NULL;
144
145         spin_lock_irqsave(&dyn_lock, flags);    
146         pdevreg = s390_search_devreg_internal(ioinfo);
147         spin_unlock_irqrestore(&dyn_lock, flags);       
148         
149         return pdevreg;
150 }
151
152 EXPORT_SYMBOL(s390_device_register);
153 EXPORT_SYMBOL(s390_device_unregister);
154