1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Device Attach routines			File: cfe_attach.c
5    *
6    *  This module manages the list of device drivers.  When a driver
7    *  is probed, it can call cfe_attach to create actual device
8    *  instances.  The routines in this module manage the
9    *  device list and the assignment of device names.
10    *
11    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
12    *
13    *********************************************************************
14    *
15    *  Copyright 2000,2001,2002,2003
16    *  Broadcom Corporation. All rights reserved.
17    *
18    *  This software is furnished under license and may be used and
19    *  copied only in accordance with the following terms and
20    *  conditions.  Subject to these conditions, you may download,
21    *  copy, install, use, modify and distribute modified or unmodified
22    *  copies of this software in source and/or binary form.  No title
23    *  or ownership is transferred hereby.
24    *
25    *  1) Any source code used, modified or distributed must reproduce
26    *     and retain this copyright notice and list of conditions
27    *     as they appear in the source file.
28    *
29    *  2) No right is granted to use any trade name, trademark, or
30    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
31    *     name may not be used to endorse or promote products derived
32    *     from this software without the prior written permission of
33    *     Broadcom Corporation.
34    *
35    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
39    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
40    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
46    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
47    *     THE POSSIBILITY OF SUCH DAMAGE.
48    ********************************************************************* */
49
50
51#include "lib_types.h"
52#include "lib_malloc.h"
53#include "lib_queue.h"
54#include "lib_printf.h"
55#include "lib_string.h"
56#include "cfe_iocb.h"
57#include "cfe_device.h"
58
59/*  *********************************************************************
60    *  Constants
61    ********************************************************************* */
62
63#define CFE_MAX_DEVINST 64		/* max # of instances of devices */
64
65/*  *********************************************************************
66    *  Globals
67    ********************************************************************* */
68
69/*
70 * Our device list.
71 */
72
73queue_t cfe_devices = {&cfe_devices, &cfe_devices};
74
75/*  *********************************************************************
76    *  cfe_finddev(name)
77    *
78    *  Locate a device in the device list by its name and return
79    *  a pointer to the device structure.
80    *
81    *  Input parameters:
82    *  	   name - name of device, e.g., "uart0"
83    *
84    *  Return value:
85    *  	   cfe_device_t pointer or NULL
86    ********************************************************************* */
87
88cfe_device_t *cfe_finddev(char *name)
89{
90    queue_t *qb;
91    cfe_device_t *dev;
92
93    for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) {
94	dev = (cfe_device_t *) qb;
95	if (strcmp(dev->dev_fullname,name) == 0) {
96	    return dev;
97	    }
98	}
99
100    return NULL;
101}
102
103
104/*  *********************************************************************
105    *  cfe_device_reset()
106    *
107    *  Call all the "reset" methods in the devices on the device
108    *  list.  Note that the methods get called even when the
109    *  devices are closed!
110    *
111    *  Input parameters:
112    *  	   nothing
113    *
114    *  Return value:
115    *  	   nothing
116    ********************************************************************* */
117
118void cfe_device_reset(void)
119{
120    queue_t *qb;
121    cfe_device_t *dev;
122
123    for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) {
124	dev = (cfe_device_t *) qb;
125	if (dev->dev_dispatch->dev_reset) {
126	    (*(dev->dev_dispatch->dev_reset))(dev->dev_softc);
127	    }
128	}
129}
130
131/*  *********************************************************************
132    *  cfe_attach_idx(drv,idx,softc,bootinfo,description)
133    *
134    *  Add a device to the device list at a specific index.  This
135    *  is mainly used for devices like SCSI disks or CD-ROMs so
136    *  we can use an index that matches the target ID or LUN.
137    *
138    *  Input parameters:
139    *  	   drv - driver structure (from the device driver module)
140    *  	   idx - requested index (e.g., uartn where 'n' is the idx)
141    *  	   softc - Unique information maintained for this device
142    *  	   bootinfo - suffix for long form of the device name.  For
143    *  	              example, scsi0.3.1  might mean SCSI controller
144    *  	              0, device ID 3, LUN 1.  The bootinfo would be
145    *  	              "3.1"
146    *  	   description - something nice to say for the devices command
147    *
148    *  Return value:
149    *  	   0 if device has already been added at this index
150    *     <0 for other problems
151    *  	   1 if we were successful.
152    ********************************************************************* */
153
154int cfe_attach_idx(cfe_driver_t *drv,int idx,void *softc,
155		   char *bootinfo,char *description)
156{
157    char name[64];
158    cfe_device_t *dev;
159
160    xsprintf(name,"%s%d",drv->drv_bootname,idx);
161
162    if (bootinfo) {
163	strcat(name,".");
164	strcat(name,bootinfo);
165	}
166
167    if (cfe_finddev(name) != NULL) {
168	return 0;
169	}
170
171    dev = (cfe_device_t *) KMALLOC(sizeof(cfe_device_t),0);
172    if (!dev) return -1;
173
174    dev->dev_fullname = strdup(name);
175    dev->dev_softc = softc;
176    dev->dev_class = drv->drv_class;
177    dev->dev_dispatch = drv->drv_dispatch;
178    dev->dev_description = description ? strdup(description) : NULL;
179    dev->dev_opencount = 0;
180
181    q_enqueue(&cfe_devices,(queue_t *) dev);
182
183    return 1;
184
185}
186
187
188
189/*  *********************************************************************
190    *  cfe_attach(drv,softc,bootinfo,description
191    *
192    *  Add a device to the system.  This is a callback from the
193    *  probe routine, and is used to actually add devices to CFE's
194    *  device list.
195    *
196    *  Input parameters:
197    *  	   drv - driver structure (from the device driver module)
198    *  	   softc - Unique information maintained for this device
199    *  	   bootinfo - suffix for long form of the device name.  For
200    *  	              example, scsi0.3.1  might mean SCSI controller
201    *  	              0, device ID 3, LUN 1.  The bootinfo would be
202    *  	              "3.1"
203    *  	   description - something nice to say for the devices command
204    *
205    *  Return value:
206    *  	   nothing
207    ********************************************************************* */
208
209void cfe_attach(cfe_driver_t *drv,void *softc,
210		char *bootinfo,
211		char *description)
212{
213    int idx;
214    int res;
215
216    /*
217     * Try device indicies 0..CFE_MAX_DEVINST to assign a unique
218     * device name for this device.  This is a really braindead way to
219     * do this, but how many devices are we expecting anyway?
220     */
221
222    for (idx = 0; idx < CFE_MAX_DEVINST; idx++) {
223
224	res = cfe_attach_idx(drv,idx,softc,bootinfo,description);
225
226	if (res < 0) break;	/* out of memory or other badness */
227	if (res > 0) break;	/* success! */
228	/* otherwise, try again, slot is taken */
229	}
230
231}
232
233/*  *********************************************************************
234    *  cfe_attach_init()
235    *
236    *  Initialize this module.
237    *
238    *  Input parameters:
239    *  	   nothing
240    *
241    *  Return value:
242    *  	   nothing
243    ********************************************************************* */
244void cfe_attach_init(void)
245{
246    q_init(&(cfe_devices));
247}
248
249
250/*  *********************************************************************
251    *  cfe_device_name(ctx)
252    *
253    *  Given a device context, return a device name
254    *
255    *  Input parameters:
256    *  	   ctx - context
257    *
258    *  Return value:
259    *  	   name
260    ********************************************************************* */
261
262char *cfe_device_name(cfe_devctx_t *ctx)
263{
264    return ctx->dev_dev->dev_fullname;
265}
266