diff options
Diffstat (limited to 'drivers/staging/cxt1e1/hwprobe.c')
-rw-r--r-- | drivers/staging/cxt1e1/hwprobe.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c new file mode 100644 index 00000000000..0f9d6539a9a --- /dev/null +++ b/drivers/staging/cxt1e1/hwprobe.c | |||
@@ -0,0 +1,400 @@ | |||
1 | /* Copyright (C) 2007 One Stop Systems | ||
2 | * Copyright (C) 2003-2005 SBE, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/hdlc.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <linux/rtnetlink.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include "pmcc4_sysdep.h" | ||
22 | #include "sbecom_inline_linux.h" | ||
23 | #include "libsbew.h" | ||
24 | #include "pmcc4_private.h" | ||
25 | #include "pmcc4.h" | ||
26 | #include "pmcc4_ioctls.h" | ||
27 | #include "pmc93x6_eeprom.h" | ||
28 | #ifdef CONFIG_PROC_FS | ||
29 | #include "sbeproc.h" | ||
30 | #endif | ||
31 | |||
32 | #ifdef SBE_INCLUDE_SYMBOLS | ||
33 | #define STATIC | ||
34 | #else | ||
35 | #define STATIC static | ||
36 | #endif | ||
37 | |||
38 | extern int log_level; | ||
39 | extern int error_flag; | ||
40 | extern int drvr_state; | ||
41 | |||
42 | /* forward references */ | ||
43 | void c4_stopwd (ci_t *); | ||
44 | struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int); | ||
45 | |||
46 | |||
47 | struct s_hdw_info hdw_info[MAX_BOARDS]; | ||
48 | |||
49 | |||
50 | void __init | ||
51 | show_two (hdw_info_t * hi, int brdno) | ||
52 | { | ||
53 | ci_t *ci; | ||
54 | struct pci_dev *pdev; | ||
55 | char *bid; | ||
56 | char *bp, banner[80]; | ||
57 | char sn[6]; | ||
58 | |||
59 | bp = banner; | ||
60 | memset (banner, 0, 80); /* clear print buffer */ | ||
61 | |||
62 | ci = (ci_t *)(netdev_priv(hi->ndev)); | ||
63 | bid = sbeid_get_bdname (ci); | ||
64 | switch (hi->promfmt) | ||
65 | { | ||
66 | case PROM_FORMAT_TYPE1: | ||
67 | memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); | ||
68 | break; | ||
69 | case PROM_FORMAT_TYPE2: | ||
70 | memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); | ||
71 | break; | ||
72 | default: | ||
73 | memset (sn, 0, 6); | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | sprintf (banner, "%s: %s S/N %06X, MUSYCC Rev %02X", | ||
78 | hi->devname, bid, | ||
79 | ((sn[3] << 16) & 0xff0000) | | ||
80 | ((sn[4] << 8) & 0x00ff00) | | ||
81 | (sn[5] & 0x0000ff), | ||
82 | (u_int8_t) hi->revid[0]); | ||
83 | |||
84 | printk ("%s\n", banner); | ||
85 | |||
86 | pdev = hi->pdev[0]; | ||
87 | printk ("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", | ||
88 | hi->devname, "MUSYCC", | ||
89 | (unsigned long) hi->addr_mapped[0], hi->addr[0], | ||
90 | hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), | ||
91 | (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); | ||
92 | |||
93 | pdev = hi->pdev[1]; | ||
94 | printk ("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", | ||
95 | hi->devname, "EBUS ", | ||
96 | (unsigned long) hi->addr_mapped[1], hi->addr[1], | ||
97 | hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), | ||
98 | (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); | ||
99 | } | ||
100 | |||
101 | |||
102 | void __init | ||
103 | hdw_sn_get (hdw_info_t * hi, int brdno) | ||
104 | { | ||
105 | /* obtain hardware EEPROM information */ | ||
106 | long addr; | ||
107 | |||
108 | addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; | ||
109 | |||
110 | /* read EEPROM with largest known format size... */ | ||
111 | pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2)); | ||
112 | |||
113 | #if 0 | ||
114 | { | ||
115 | unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; | ||
116 | |||
117 | printk ("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
118 | *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); | ||
119 | printk ("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
120 | *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); | ||
121 | printk ("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
122 | *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); | ||
123 | printk ("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
124 | *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); | ||
125 | printk ("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
126 | *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); | ||
127 | printk ("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
128 | *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); | ||
129 | } | ||
130 | #endif | ||
131 | #if 0 | ||
132 | printk ("sn: %x %x %x %x %x %x\n", | ||
133 | hi->mfg_info.Serial[0], | ||
134 | hi->mfg_info.Serial[1], | ||
135 | hi->mfg_info.Serial[2], | ||
136 | hi->mfg_info.Serial[3], | ||
137 | hi->mfg_info.Serial[4], | ||
138 | hi->mfg_info.Serial[5]); | ||
139 | #endif | ||
140 | |||
141 | if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) | ||
142 | { | ||
143 | /* bad crc, data is suspect */ | ||
144 | if (log_level >= LOG_WARN) | ||
145 | printk ("%s: EEPROM cksum error\n", hi->devname); | ||
146 | hi->mfg_info_sts = EEPROM_CRCERR; | ||
147 | } else | ||
148 | hi->mfg_info_sts = EEPROM_OK; | ||
149 | } | ||
150 | |||
151 | |||
152 | void __init | ||
153 | prep_hdw_info (void) | ||
154 | { | ||
155 | hdw_info_t *hi; | ||
156 | int i; | ||
157 | |||
158 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
159 | { | ||
160 | hi->pci_busno = 0xff; | ||
161 | hi->pci_slot = 0xff; | ||
162 | hi->pci_pin[0] = 0; | ||
163 | hi->pci_pin[1] = 0; | ||
164 | hi->ndev = 0; | ||
165 | hi->addr[0] = 0L; | ||
166 | hi->addr[1] = 0L; | ||
167 | hi->addr_mapped[0] = 0L; | ||
168 | hi->addr_mapped[1] = 0L; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | void | ||
173 | cleanup_ioremap (void) | ||
174 | { | ||
175 | hdw_info_t *hi; | ||
176 | int i; | ||
177 | |||
178 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
179 | { | ||
180 | if (hi->pci_slot == 0xff) | ||
181 | break; | ||
182 | if (hi->addr_mapped[0]) | ||
183 | { | ||
184 | iounmap ((void *) (hi->addr_mapped[0])); | ||
185 | release_mem_region ((long) hi->addr[0], hi->len[0]); | ||
186 | hi->addr_mapped[0] = 0; | ||
187 | } | ||
188 | if (hi->addr_mapped[1]) | ||
189 | { | ||
190 | iounmap ((void *) (hi->addr_mapped[1])); | ||
191 | release_mem_region ((long) hi->addr[1], hi->len[1]); | ||
192 | hi->addr_mapped[1] = 0; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | |||
198 | void | ||
199 | cleanup_devs (void) | ||
200 | { | ||
201 | hdw_info_t *hi; | ||
202 | int i; | ||
203 | |||
204 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
205 | { | ||
206 | if (hi->pci_slot == 0xff || !hi->ndev) | ||
207 | break; | ||
208 | c4_stopwd(netdev_priv(hi->ndev)); | ||
209 | #ifdef CONFIG_PROC_FS | ||
210 | sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); | ||
211 | #endif | ||
212 | unregister_netdev (hi->ndev); | ||
213 | free_irq (hi->pdev[0]->irq, hi->ndev); | ||
214 | #ifdef CONFIG_SBE_PMCC4_NCOMM | ||
215 | free_irq (hi->pdev[1]->irq, hi->ndev); | ||
216 | #endif | ||
217 | OS_kfree (hi->ndev); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | |||
222 | STATIC int __init | ||
223 | c4_hdw_init (struct pci_dev * pdev, int found) | ||
224 | { | ||
225 | hdw_info_t *hi; | ||
226 | int i; | ||
227 | int fun, slot; | ||
228 | unsigned char busno = 0xff; | ||
229 | |||
230 | /* our MUSYCC chip supports two functions, 0 & 1 */ | ||
231 | if ((fun = PCI_FUNC (pdev->devfn)) > 1) | ||
232 | { | ||
233 | printk (KERN_WARNING "%s: unexpected devfun: 0x%x\n", THIS_MODULE->name, pdev->devfn); | ||
234 | return 0; | ||
235 | } | ||
236 | if (pdev->bus) /* obtain bus number */ | ||
237 | busno = pdev->bus->number; | ||
238 | else | ||
239 | busno = 0; /* default for system PCI inconsistency */ | ||
240 | slot = pdev->devfn & ~0x07; | ||
241 | |||
242 | /* | ||
243 | * Functions 0 & 1 for a given board (identified by same bus(busno) and | ||
244 | * slot(slot)) are placed into the same 'hardware' structure. The first | ||
245 | * part of the board's functionality will be placed into an unpopulated | ||
246 | * element, identified by "slot==(0xff)". The second part of a board's | ||
247 | * functionality will match the previously loaded slot/busno. | ||
248 | */ | ||
249 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
250 | { | ||
251 | /* | ||
252 | * match with board's first found interface, otherwise this is first | ||
253 | * found | ||
254 | */ | ||
255 | if ((hi->pci_slot == 0xff) || /* new board */ | ||
256 | ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) | ||
257 | break; /* found for-loop exit */ | ||
258 | } | ||
259 | if (i == MAX_BOARDS) /* no match in above loop means MAX | ||
260 | * exceeded */ | ||
261 | { | ||
262 | printk (KERN_WARNING "%s: exceeded number of allowed devices (>%d)?\n", | ||
263 | THIS_MODULE->name, MAX_BOARDS); | ||
264 | return 0; | ||
265 | } | ||
266 | if (pdev->bus) | ||
267 | hi->pci_busno = pdev->bus->number; | ||
268 | else | ||
269 | hi->pci_busno = 0; /* default for system PCI inconsistency */ | ||
270 | hi->pci_slot = slot; | ||
271 | pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); | ||
272 | pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]); | ||
273 | hi->bus = pdev->bus; | ||
274 | hi->addr[fun] = pci_resource_start (pdev, 0); | ||
275 | hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1; | ||
276 | hi->pdev[fun] = pdev; | ||
277 | |||
278 | { | ||
279 | /* | ||
280 | * create device name from module name, plus add the appropriate | ||
281 | * board number | ||
282 | */ | ||
283 | char *cp = hi->devname; | ||
284 | |||
285 | strcpy (cp, THIS_MODULE->name); | ||
286 | cp += strlen (cp); /* reposition */ | ||
287 | *cp++ = '-'; | ||
288 | *cp++ = '0' + (found / 2); /* there are two found interfaces per | ||
289 | * board */ | ||
290 | *cp = 0; /* termination */ | ||
291 | } | ||
292 | |||
293 | return 1; | ||
294 | } | ||
295 | |||
296 | |||
297 | status_t __init | ||
298 | c4hw_attach_all (void) | ||
299 | { | ||
300 | hdw_info_t *hi; | ||
301 | struct pci_dev *pdev = NULL; | ||
302 | int found = 0, i, j; | ||
303 | |||
304 | error_flag = 0; | ||
305 | prep_hdw_info (); | ||
306 | /*** scan PCI bus for all possible boards */ | ||
307 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | ||
308 | while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT, | ||
309 | PCI_DEVICE_ID_CN8474, | ||
310 | pdev))) | ||
311 | #else | ||
312 | while ((pdev = pci_find_device (PCI_VENDOR_ID_CONEXANT, | ||
313 | PCI_DEVICE_ID_CN8474, | ||
314 | pdev))) | ||
315 | #endif | ||
316 | { | ||
317 | if (c4_hdw_init (pdev, found)) | ||
318 | found++; | ||
319 | } | ||
320 | if (!found) | ||
321 | { | ||
322 | printk (KERN_WARNING "%s: No boards found.\n", THIS_MODULE->name); | ||
323 | return ENODEV; | ||
324 | } | ||
325 | /* sanity check for consistant hardware found */ | ||
326 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
327 | { | ||
328 | if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) | ||
329 | { | ||
330 | printk (KERN_WARNING "%s: something very wrong with pci_get_device.\n", hi->devname); | ||
331 | return EIO; | ||
332 | } | ||
333 | } | ||
334 | /* bring board's memory regions on/line */ | ||
335 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
336 | { | ||
337 | if (hi->pci_slot == 0xff) | ||
338 | break; | ||
339 | for (j = 0; j < 2; j++) | ||
340 | { | ||
341 | if (request_mem_region (hi->addr[j], hi->len[j], hi->devname) == 0) | ||
342 | { | ||
343 | printk (KERN_WARNING "%s: memory in use, addr=0x%lx, len=0x%lx ?\n", | ||
344 | hi->devname, hi->addr[j], hi->len[j]); | ||
345 | cleanup_ioremap (); | ||
346 | return ENOMEM; | ||
347 | } | ||
348 | hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); | ||
349 | if (!hi->addr_mapped[j]) | ||
350 | { | ||
351 | printk (KERN_WARNING "%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", | ||
352 | hi->devname, hi->addr[j], hi->len[j]); | ||
353 | cleanup_ioremap (); | ||
354 | return ENOMEM; | ||
355 | } | ||
356 | #ifdef SBE_MAP_DEBUG | ||
357 | printk (KERN_WARNING "%s: io remapped from phys %x to virt %x\n", | ||
358 | hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]); | ||
359 | #endif | ||
360 | } | ||
361 | } | ||
362 | |||
363 | drvr_state = SBE_DRVR_AVAILABLE; | ||
364 | |||
365 | /* Have now memory mapped all boards. Now allow board's access to system */ | ||
366 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | ||
367 | { | ||
368 | if (hi->pci_slot == 0xff) | ||
369 | break; | ||
370 | if (pci_enable_device (hi->pdev[0]) || | ||
371 | pci_enable_device (hi->pdev[1])) | ||
372 | { | ||
373 | drvr_state = SBE_DRVR_DOWN; | ||
374 | printk (KERN_WARNING "%s: failed to enable card %d slot %d\n", | ||
375 | hi->devname, i, hi->pci_slot); | ||
376 | cleanup_devs (); | ||
377 | cleanup_ioremap (); | ||
378 | return EIO; | ||
379 | } | ||
380 | pci_set_master (hi->pdev[0]); | ||
381 | pci_set_master (hi->pdev[1]); | ||
382 | if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0], | ||
383 | (long) hi->addr_mapped[1], | ||
384 | hi->pdev[0]->irq, | ||
385 | hi->pdev[1]->irq))) | ||
386 | { | ||
387 | drvr_state = SBE_DRVR_DOWN; | ||
388 | cleanup_ioremap (); | ||
389 | /* NOTE: c4_add_dev() does its own device cleanup */ | ||
390 | #if 0 | ||
391 | cleanup_devs (); | ||
392 | #endif | ||
393 | return error_flag; /* error_flag set w/in add_dev() */ | ||
394 | } | ||
395 | show_two (hi, i); /* displays found information */ | ||
396 | } | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | /*** End-of-File ***/ | ||