Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * CompactPCI Hot Plug Driver PCI functions
  3  *
  4  * Copyright (C) 2002,2005 by SOMA Networks, Inc.
  5  *
  6  * All rights reserved.
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or (at
 11  * your option) any later version.
 12  *
 13  * This program is distributed in the hope that it will be useful, but
 14  * WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 16  * NON INFRINGEMENT.  See the GNU General Public License for more
 17  * details.
 18  *
 19  * You should have received a copy of the GNU General Public License
 20  * along with this program; if not, write to the Free Software
 21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 22  *
 23  * Send feedback to <scottm@somanetworks.com>
 24  */
 25 
 26 #include <linux/module.h>
 27 #include <linux/kernel.h>
 28 #include <linux/pci.h>
 29 #include <linux/pci_hotplug.h>
 30 #include <linux/proc_fs.h>
 31 #include "../pci.h"
 32 #include "cpci_hotplug.h"
 33 
 34 #define MY_NAME "cpci_hotplug"
 35 
 36 extern int cpci_debug;
 37 
 38 #define dbg(format, arg...)                                     \
 39         do {                                                    \
 40                 if (cpci_debug)                                 \
 41                         printk (KERN_DEBUG "%s: " format "\n",  \
 42                                 MY_NAME , ## arg);              \
 43         } while (0)
 44 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
 45 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
 46 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
 47 
 48 
 49 u8 cpci_get_attention_status(struct slot* slot)
 50 {
 51         int hs_cap;
 52         u16 hs_csr;
 53 
 54         hs_cap = pci_bus_find_capability(slot->bus,
 55                                          slot->devfn,
 56                                          PCI_CAP_ID_CHSWP);
 57         if (!hs_cap)
 58                 return 0;
 59 
 60         if (pci_bus_read_config_word(slot->bus,
 61                                      slot->devfn,
 62                                      hs_cap + 2,
 63                                      &hs_csr))
 64                 return 0;
 65 
 66         return hs_csr & 0x0008 ? 1 : 0;
 67 }
 68 
 69 int cpci_set_attention_status(struct slot* slot, int status)
 70 {
 71         int hs_cap;
 72         u16 hs_csr;
 73 
 74         hs_cap = pci_bus_find_capability(slot->bus,
 75                                          slot->devfn,
 76                                          PCI_CAP_ID_CHSWP);
 77         if (!hs_cap)
 78                 return 0;
 79         if (pci_bus_read_config_word(slot->bus,
 80                                      slot->devfn,
 81                                      hs_cap + 2,
 82                                      &hs_csr))
 83                 return 0;
 84         if (status)
 85                 hs_csr |= HS_CSR_LOO;
 86         else
 87                 hs_csr &= ~HS_CSR_LOO;
 88         if (pci_bus_write_config_word(slot->bus,
 89                                       slot->devfn,
 90                                       hs_cap + 2,
 91                                       hs_csr))
 92                 return 0;
 93         return 1;
 94 }
 95 
 96 u16 cpci_get_hs_csr(struct slot* slot)
 97 {
 98         int hs_cap;
 99         u16 hs_csr;
100 
101         hs_cap = pci_bus_find_capability(slot->bus,
102                                          slot->devfn,
103                                          PCI_CAP_ID_CHSWP);
104         if (!hs_cap)
105                 return 0xFFFF;
106         if (pci_bus_read_config_word(slot->bus,
107                                      slot->devfn,
108                                      hs_cap + 2,
109                                      &hs_csr))
110                 return 0xFFFF;
111         return hs_csr;
112 }
113 
114 int cpci_check_and_clear_ins(struct slot* slot)
115 {
116         int hs_cap;
117         u16 hs_csr;
118         int ins = 0;
119 
120         hs_cap = pci_bus_find_capability(slot->bus,
121                                          slot->devfn,
122                                          PCI_CAP_ID_CHSWP);
123         if (!hs_cap)
124                 return 0;
125         if (pci_bus_read_config_word(slot->bus,
126                                      slot->devfn,
127                                      hs_cap + 2,
128                                      &hs_csr))
129                 return 0;
130         if (hs_csr & HS_CSR_INS) {
131                 /* Clear INS (by setting it) */
132                 if (pci_bus_write_config_word(slot->bus,
133                                               slot->devfn,
134                                               hs_cap + 2,
135                                               hs_csr))
136                         ins = 0;
137                 else
138                         ins = 1;
139         }
140         return ins;
141 }
142 
143 int cpci_check_ext(struct slot* slot)
144 {
145         int hs_cap;
146         u16 hs_csr;
147         int ext = 0;
148 
149         hs_cap = pci_bus_find_capability(slot->bus,
150                                          slot->devfn,
151                                          PCI_CAP_ID_CHSWP);
152         if (!hs_cap)
153                 return 0;
154         if (pci_bus_read_config_word(slot->bus,
155                                      slot->devfn,
156                                      hs_cap + 2,
157                                      &hs_csr))
158                 return 0;
159         if (hs_csr & HS_CSR_EXT)
160                 ext = 1;
161         return ext;
162 }
163 
164 int cpci_clear_ext(struct slot* slot)
165 {
166         int hs_cap;
167         u16 hs_csr;
168 
169         hs_cap = pci_bus_find_capability(slot->bus,
170                                          slot->devfn,
171                                          PCI_CAP_ID_CHSWP);
172         if (!hs_cap)
173                 return -ENODEV;
174         if (pci_bus_read_config_word(slot->bus,
175                                      slot->devfn,
176                                      hs_cap + 2,
177                                      &hs_csr))
178                 return -ENODEV;
179         if (hs_csr & HS_CSR_EXT) {
180                 /* Clear EXT (by setting it) */
181                 if (pci_bus_write_config_word(slot->bus,
182                                               slot->devfn,
183                                               hs_cap + 2,
184                                               hs_csr))
185                         return -ENODEV;
186         }
187         return 0;
188 }
189 
190 int cpci_led_on(struct slot* slot)
191 {
192         int hs_cap;
193         u16 hs_csr;
194 
195         hs_cap = pci_bus_find_capability(slot->bus,
196                                          slot->devfn,
197                                          PCI_CAP_ID_CHSWP);
198         if (!hs_cap)
199                 return -ENODEV;
200         if (pci_bus_read_config_word(slot->bus,
201                                      slot->devfn,
202                                      hs_cap + 2,
203                                      &hs_csr))
204                 return -ENODEV;
205         if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
206                 hs_csr |= HS_CSR_LOO;
207                 if (pci_bus_write_config_word(slot->bus,
208                                               slot->devfn,
209                                               hs_cap + 2,
210                                               hs_csr)) {
211                         err("Could not set LOO for slot %s",
212                             slot->hotplug_slot->name);
213                         return -ENODEV;
214                 }
215         }
216         return 0;
217 }
218 
219 int cpci_led_off(struct slot* slot)
220 {
221         int hs_cap;
222         u16 hs_csr;
223 
224         hs_cap = pci_bus_find_capability(slot->bus,
225                                          slot->devfn,
226                                          PCI_CAP_ID_CHSWP);
227         if (!hs_cap)
228                 return -ENODEV;
229         if (pci_bus_read_config_word(slot->bus,
230                                      slot->devfn,
231                                      hs_cap + 2,
232                                      &hs_csr))
233                 return -ENODEV;
234         if (hs_csr & HS_CSR_LOO) {
235                 hs_csr &= ~HS_CSR_LOO;
236                 if (pci_bus_write_config_word(slot->bus,
237                                               slot->devfn,
238                                               hs_cap + 2,
239                                               hs_csr)) {
240                         err("Could not clear LOO for slot %s",
241                             slot->hotplug_slot->name);
242                         return -ENODEV;
243                 }
244         }
245         return 0;
246 }
247 
248 
249 /*
250  * Device configuration functions
251  */
252 
253 int __ref cpci_configure_slot(struct slot *slot)
254 {
255         struct pci_bus *parent;
256         int fn;
257 
258         dbg("%s - enter", __FUNCTION__);
259 
260         if (slot->dev == NULL) {
261                 dbg("pci_dev null, finding %02x:%02x:%x",
262                     slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
263                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
264         }
265 
266         /* Still NULL? Well then scan for it! */
267         if (slot->dev == NULL) {
268                 int n;
269                 dbg("pci_dev still null");
270 
271                 /*
272                  * This will generate pci_dev structures for all functions, but
273                  * we will only call this case when lookup fails.
274                  */
275                 n = pci_scan_slot(slot->bus, slot->devfn);
276                 dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
277                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
278                 if (slot->dev == NULL) {
279                         err("Could not find PCI device for slot %02x", slot->number);
280                         return -ENODEV;
281                 }
282         }
283         parent = slot->dev->bus;
284 
285         for (fn = 0; fn < 8; fn++) {
286                 struct pci_dev *dev;
287 
288                 dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
289                 if (!dev)
290                         continue;
291                 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
292                     (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
293                         /* Find an unused bus number for the new bridge */
294                         struct pci_bus *child;
295                         unsigned char busnr, start = parent->secondary;
296                         unsigned char end = parent->subordinate;
297 
298                         for (busnr = start; busnr <= end; busnr++) {
299                                 if (!pci_find_bus(pci_domain_nr(parent),
300                                                   busnr))
301                                         break;
302                         }
303                         if (busnr >= end) {
304                                 err("No free bus for hot-added bridge\n");
305                                 pci_dev_put(dev);
306                                 continue;
307                         }
308                         child = pci_add_new_bus(parent, dev, busnr);
309                         if (!child) {
310                                 err("Cannot add new bus for %s\n",
311                                     pci_name(dev));
312                                 pci_dev_put(dev);
313                                 continue;
314                         }
315                         child->subordinate = pci_do_scan_bus(child);
316                         pci_bus_size_bridges(child);
317                 }
318                 pci_dev_put(dev);
319         }
320 
321         pci_bus_assign_resources(parent);
322         pci_bus_add_devices(parent);
323         pci_enable_bridges(parent);
324 
325         dbg("%s - exit", __FUNCTION__);
326         return 0;
327 }
328 
329 int cpci_unconfigure_slot(struct slot* slot)
330 {
331         int i;
332         struct pci_dev *dev;
333 
334         dbg("%s - enter", __FUNCTION__);
335         if (!slot->dev) {
336                 err("No device for slot %02x\n", slot->number);
337                 return -ENODEV;
338         }
339 
340         for (i = 0; i < 8; i++) {
341                 dev = pci_get_slot(slot->bus,
342                                     PCI_DEVFN(PCI_SLOT(slot->devfn), i));
343                 if (dev) {
344                         pci_remove_bus_device(dev);
345                         pci_dev_put(dev);
346                 }
347         }
348         pci_dev_put(slot->dev);
349         slot->dev = NULL;
350 
351         dbg("%s - exit", __FUNCTION__);
352         return 0;
353 }
354 
  This page was automatically generated by the LXR engine.