1d58fda43Sjbeloro /*
2d58fda43Sjbeloro * CDDL HEADER START
3d58fda43Sjbeloro *
4d58fda43Sjbeloro * The contents of this file are subject to the terms of the
5*19397407SSherry Moore * Common Development and Distribution License (the "License").
6*19397407SSherry Moore * You may not use this file except in compliance with the License.
7d58fda43Sjbeloro *
8d58fda43Sjbeloro * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d58fda43Sjbeloro * or http://www.opensolaris.org/os/licensing.
10d58fda43Sjbeloro * See the License for the specific language governing permissions
11d58fda43Sjbeloro * and limitations under the License.
12d58fda43Sjbeloro *
13d58fda43Sjbeloro * When distributing Covered Code, include this CDDL HEADER in each
14d58fda43Sjbeloro * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d58fda43Sjbeloro * If applicable, add the following below this CDDL HEADER, with the
16d58fda43Sjbeloro * fields enclosed by brackets "[]" replaced with your own identifying
17d58fda43Sjbeloro * information: Portions Copyright [yyyy] [name of copyright owner]
18d58fda43Sjbeloro *
19d58fda43Sjbeloro * CDDL HEADER END
20d58fda43Sjbeloro */
21d58fda43Sjbeloro
22d58fda43Sjbeloro /*
23*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24d58fda43Sjbeloro * Use is subject to license terms.
25d58fda43Sjbeloro */
26d58fda43Sjbeloro
27d58fda43Sjbeloro
28d58fda43Sjbeloro /*
29d58fda43Sjbeloro * Driver to control Alert and Power LEDs for the Seattle platform.
30d58fda43Sjbeloro * Alert LED is also known as Service (required).
31d58fda43Sjbeloro * Power LED is also known as Activity.
32d58fda43Sjbeloro */
33d58fda43Sjbeloro #include <sys/types.h>
34d58fda43Sjbeloro #include <sys/time.h>
35d58fda43Sjbeloro #include <sys/errno.h>
36d58fda43Sjbeloro #include <sys/cmn_err.h>
37d58fda43Sjbeloro #include <sys/param.h>
38d58fda43Sjbeloro #include <sys/modctl.h>
39d58fda43Sjbeloro #include <sys/conf.h>
40d58fda43Sjbeloro #include <sys/open.h>
41d58fda43Sjbeloro #include <sys/stat.h>
42d58fda43Sjbeloro #include <sys/clock.h>
43d58fda43Sjbeloro #include <sys/ddi.h>
44d58fda43Sjbeloro #include <sys/sunddi.h>
45d58fda43Sjbeloro #include <sys/file.h>
46d58fda43Sjbeloro #include <sys/note.h>
47d58fda43Sjbeloro #include <sys/epic.h>
48d58fda43Sjbeloro
49d58fda43Sjbeloro
50d58fda43Sjbeloro /*
51d58fda43Sjbeloro * Some #defs that must be here as they differ for power.c
52d58fda43Sjbeloro * and epic.c
53d58fda43Sjbeloro */
54d58fda43Sjbeloro #define EPIC_REGS_OFFSET 0x00
55d58fda43Sjbeloro #define EPIC_REGS_LEN 0x80
56d58fda43Sjbeloro
57d58fda43Sjbeloro #define EPIC_IND_DATA 0x40
58d58fda43Sjbeloro #define EPIC_IND_ADDR 0x41
59d58fda43Sjbeloro #define EPIC_WRITE_MASK 0x80
60d58fda43Sjbeloro
61d58fda43Sjbeloro /* dev_ops and cb_ops entry point function declarations */
62d58fda43Sjbeloro static int epic_attach(dev_info_t *, ddi_attach_cmd_t);
63d58fda43Sjbeloro static int epic_detach(dev_info_t *, ddi_detach_cmd_t);
64d58fda43Sjbeloro static int epic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
65d58fda43Sjbeloro static int epic_open(dev_t *, int, int, cred_t *);
66d58fda43Sjbeloro static int epic_close(dev_t, int, int, cred_t *);
67d58fda43Sjbeloro static int epic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
68d58fda43Sjbeloro
69d58fda43Sjbeloro struct cb_ops epic_cb_ops = {
70d58fda43Sjbeloro epic_open, /* open */
71d58fda43Sjbeloro epic_close, /* close */
72d58fda43Sjbeloro nodev, /* strategy */
73d58fda43Sjbeloro nodev, /* print */
74d58fda43Sjbeloro nodev, /* dump */
75d58fda43Sjbeloro nodev, /* read */
76d58fda43Sjbeloro nodev, /* write */
77d58fda43Sjbeloro epic_ioctl, /* ioctl */
78d58fda43Sjbeloro nodev, /* devmap */
79d58fda43Sjbeloro nodev, /* mmap */
80d58fda43Sjbeloro ddi_segmap, /* segmap */
81d58fda43Sjbeloro nochpoll, /* poll */
82d58fda43Sjbeloro ddi_prop_op, /* cb_prop_op */
83d58fda43Sjbeloro NULL, /* streamtab - for STREAMS drivers */
84d58fda43Sjbeloro D_NEW | D_MP /* driver compatibility flag */
85d58fda43Sjbeloro };
86d58fda43Sjbeloro
87d58fda43Sjbeloro static struct dev_ops epic_dev_ops = {
88d58fda43Sjbeloro DEVO_REV, /* driver build version */
89d58fda43Sjbeloro 0, /* device reference count */
90d58fda43Sjbeloro epic_getinfo,
91d58fda43Sjbeloro nulldev,
92d58fda43Sjbeloro nulldev, /* probe */
93d58fda43Sjbeloro epic_attach,
94d58fda43Sjbeloro epic_detach,
95d58fda43Sjbeloro nulldev, /* reset */
96d58fda43Sjbeloro &epic_cb_ops,
97d58fda43Sjbeloro (struct bus_ops *)NULL,
98*19397407SSherry Moore nulldev, /* power */
99*19397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
100d58fda43Sjbeloro };
101d58fda43Sjbeloro
102d58fda43Sjbeloro
103d58fda43Sjbeloro /*
104d58fda43Sjbeloro * Soft state
105d58fda43Sjbeloro */
106d58fda43Sjbeloro struct epic_softc {
107d58fda43Sjbeloro dev_info_t *dip;
108d58fda43Sjbeloro kmutex_t mutex;
109d58fda43Sjbeloro uint8_t *cmd_reg;
110d58fda43Sjbeloro ddi_acc_handle_t cmd_handle;
111d58fda43Sjbeloro };
112d58fda43Sjbeloro
113d58fda43Sjbeloro #define getsoftc(inst) ((struct epic_softc *)ddi_get_soft_state(statep, \
114d58fda43Sjbeloro (inst)))
115d58fda43Sjbeloro
116d58fda43Sjbeloro /* module configuration stuff */
117d58fda43Sjbeloro static void *statep;
118d58fda43Sjbeloro extern struct mod_ops mod_driverops;
119d58fda43Sjbeloro
120d58fda43Sjbeloro static struct modldrv modldrv = {
121d58fda43Sjbeloro &mod_driverops,
122*19397407SSherry Moore "epic_client driver",
123d58fda43Sjbeloro &epic_dev_ops
124d58fda43Sjbeloro };
125d58fda43Sjbeloro
126d58fda43Sjbeloro static struct modlinkage modlinkage = {
127d58fda43Sjbeloro MODREV_1,
128d58fda43Sjbeloro &modldrv,
129d58fda43Sjbeloro 0
130d58fda43Sjbeloro };
131d58fda43Sjbeloro
132d58fda43Sjbeloro int
_init(void)133d58fda43Sjbeloro _init(void)
134d58fda43Sjbeloro {
135d58fda43Sjbeloro int e;
136d58fda43Sjbeloro
137d58fda43Sjbeloro if ((e = ddi_soft_state_init(&statep,
138d58fda43Sjbeloro sizeof (struct epic_softc), 0)) != 0) {
139d58fda43Sjbeloro return (e);
140d58fda43Sjbeloro }
141d58fda43Sjbeloro
142d58fda43Sjbeloro if ((e = mod_install(&modlinkage)) != 0)
143d58fda43Sjbeloro ddi_soft_state_fini(&statep);
144d58fda43Sjbeloro
145d58fda43Sjbeloro return (e);
146d58fda43Sjbeloro }
147d58fda43Sjbeloro
148d58fda43Sjbeloro int
_fini(void)149d58fda43Sjbeloro _fini(void)
150d58fda43Sjbeloro {
151d58fda43Sjbeloro int e;
152d58fda43Sjbeloro
153d58fda43Sjbeloro if ((e = mod_remove(&modlinkage)) != 0)
154d58fda43Sjbeloro return (e);
155d58fda43Sjbeloro
156d58fda43Sjbeloro ddi_soft_state_fini(&statep);
157d58fda43Sjbeloro
158d58fda43Sjbeloro return (DDI_SUCCESS);
159d58fda43Sjbeloro }
160d58fda43Sjbeloro
161d58fda43Sjbeloro int
_info(struct modinfo * modinfop)162d58fda43Sjbeloro _info(struct modinfo *modinfop)
163d58fda43Sjbeloro {
164d58fda43Sjbeloro return (mod_info(&modlinkage, modinfop));
165d58fda43Sjbeloro }
166d58fda43Sjbeloro
167d58fda43Sjbeloro /*ARGSUSED*/
168d58fda43Sjbeloro static int
epic_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)169d58fda43Sjbeloro epic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
170d58fda43Sjbeloro {
171d58fda43Sjbeloro int inst;
172d58fda43Sjbeloro int retval = DDI_SUCCESS;
173d58fda43Sjbeloro struct epic_softc *softc;
174d58fda43Sjbeloro
175d58fda43Sjbeloro inst = (getminor((dev_t)arg));
176d58fda43Sjbeloro
177d58fda43Sjbeloro switch (cmd) {
178d58fda43Sjbeloro case DDI_INFO_DEVT2DEVINFO:
179d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) {
180d58fda43Sjbeloro *result = (void *)NULL;
181d58fda43Sjbeloro retval = DDI_FAILURE;
182d58fda43Sjbeloro } else
183d58fda43Sjbeloro *result = (void *)softc->dip;
184d58fda43Sjbeloro break;
185d58fda43Sjbeloro
186d58fda43Sjbeloro case DDI_INFO_DEVT2INSTANCE:
187bd9d7d01Sanovick *result = (void *)(uintptr_t)inst;
188d58fda43Sjbeloro break;
189d58fda43Sjbeloro
190d58fda43Sjbeloro default:
191d58fda43Sjbeloro retval = DDI_FAILURE;
192d58fda43Sjbeloro }
193d58fda43Sjbeloro
194d58fda43Sjbeloro return (retval);
195d58fda43Sjbeloro }
196d58fda43Sjbeloro
197d58fda43Sjbeloro static int
epic_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)198d58fda43Sjbeloro epic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
199d58fda43Sjbeloro {
200d58fda43Sjbeloro int inst;
201d58fda43Sjbeloro struct epic_softc *softc = NULL;
202d58fda43Sjbeloro int minor;
203d58fda43Sjbeloro char name[MAXNAMELEN];
204d58fda43Sjbeloro ddi_device_acc_attr_t dev_attr;
205d58fda43Sjbeloro int res;
206d58fda43Sjbeloro
207d58fda43Sjbeloro switch (cmd) {
208d58fda43Sjbeloro case DDI_ATTACH:
209d58fda43Sjbeloro inst = ddi_get_instance(dip);
210d58fda43Sjbeloro (void) sprintf(name, "env-monitor%d", inst);
211d58fda43Sjbeloro minor = inst;
212d58fda43Sjbeloro if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
213d58fda43Sjbeloro DDI_PSEUDO, NULL) == DDI_FAILURE) {
214d58fda43Sjbeloro cmn_err(CE_WARN,
215d58fda43Sjbeloro "ddi_create_minor_node() failed for inst %d\n",
216d58fda43Sjbeloro inst);
217d58fda43Sjbeloro return (DDI_FAILURE);
218d58fda43Sjbeloro }
219d58fda43Sjbeloro
220d58fda43Sjbeloro /* Allocate a soft state structure for this instance */
221d58fda43Sjbeloro if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) {
222d58fda43Sjbeloro cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed "
223d58fda43Sjbeloro "for inst %d\n", inst);
224d58fda43Sjbeloro break;
225d58fda43Sjbeloro }
226d58fda43Sjbeloro
227d58fda43Sjbeloro /* Setup soft state */
228d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) {
229d58fda43Sjbeloro break;
230d58fda43Sjbeloro }
231d58fda43Sjbeloro softc->dip = dip;
232d58fda43Sjbeloro mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
233d58fda43Sjbeloro
234d58fda43Sjbeloro /* Setup device attributes */
235d58fda43Sjbeloro dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
236d58fda43Sjbeloro dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
237d58fda43Sjbeloro dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
238d58fda43Sjbeloro
239d58fda43Sjbeloro res = ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->cmd_reg,
240d58fda43Sjbeloro EPIC_REGS_OFFSET, EPIC_REGS_LEN, &dev_attr,
241d58fda43Sjbeloro &softc->cmd_handle);
242d58fda43Sjbeloro
243d58fda43Sjbeloro if (res != DDI_SUCCESS) {
244d58fda43Sjbeloro cmn_err(CE_WARN, "ddi_regs_map_setup() failed\n");
245d58fda43Sjbeloro break;
246d58fda43Sjbeloro }
247d58fda43Sjbeloro
248d58fda43Sjbeloro ddi_report_dev(dip);
249d58fda43Sjbeloro
250d58fda43Sjbeloro
251d58fda43Sjbeloro return (DDI_SUCCESS);
252d58fda43Sjbeloro
253d58fda43Sjbeloro case DDI_RESUME:
254d58fda43Sjbeloro return (DDI_SUCCESS);
255d58fda43Sjbeloro
256d58fda43Sjbeloro default:
257d58fda43Sjbeloro return (DDI_FAILURE);
258d58fda43Sjbeloro }
259d58fda43Sjbeloro
260d58fda43Sjbeloro /* Attach failed */
261d58fda43Sjbeloro /* Free soft state, if allocated. remove minor node if added earlier */
262d58fda43Sjbeloro if (softc)
263d58fda43Sjbeloro ddi_soft_state_free(statep, inst);
264d58fda43Sjbeloro
265d58fda43Sjbeloro ddi_remove_minor_node(dip, NULL);
266d58fda43Sjbeloro
267d58fda43Sjbeloro return (DDI_FAILURE);
268d58fda43Sjbeloro }
269d58fda43Sjbeloro
270d58fda43Sjbeloro static int
epic_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)271d58fda43Sjbeloro epic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
272d58fda43Sjbeloro {
273d58fda43Sjbeloro int inst;
274d58fda43Sjbeloro struct epic_softc *softc;
275d58fda43Sjbeloro
276d58fda43Sjbeloro switch (cmd) {
277d58fda43Sjbeloro case DDI_DETACH:
278d58fda43Sjbeloro inst = ddi_get_instance(dip);
279d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL)
280d58fda43Sjbeloro return (ENXIO);
281d58fda43Sjbeloro
282d58fda43Sjbeloro (void) ddi_regs_map_free(&softc->cmd_handle);
283d58fda43Sjbeloro
284d58fda43Sjbeloro
285d58fda43Sjbeloro /* Free the soft state and remove minor node added earlier */
286d58fda43Sjbeloro mutex_destroy(&softc->mutex);
287d58fda43Sjbeloro ddi_soft_state_free(statep, inst);
288d58fda43Sjbeloro ddi_remove_minor_node(dip, NULL);
289d58fda43Sjbeloro return (DDI_SUCCESS);
290d58fda43Sjbeloro
291d58fda43Sjbeloro case DDI_SUSPEND:
292d58fda43Sjbeloro return (DDI_SUCCESS);
293d58fda43Sjbeloro
294d58fda43Sjbeloro default:
295d58fda43Sjbeloro return (DDI_FAILURE);
296d58fda43Sjbeloro }
297d58fda43Sjbeloro }
298d58fda43Sjbeloro
299d58fda43Sjbeloro /*ARGSUSED*/
300d58fda43Sjbeloro static int
epic_open(dev_t * devp,int flag,int otyp,cred_t * credp)301d58fda43Sjbeloro epic_open(dev_t *devp, int flag, int otyp, cred_t *credp)
302d58fda43Sjbeloro {
303d58fda43Sjbeloro _NOTE(ARGUNUSED(flag))
304d58fda43Sjbeloro _NOTE(ARGUNUSED(otyp))
305d58fda43Sjbeloro _NOTE(ARGUNUSED(credp))
306d58fda43Sjbeloro
307d58fda43Sjbeloro int inst = getminor(*devp);
308d58fda43Sjbeloro
309d58fda43Sjbeloro return (getsoftc(inst) == NULL ? ENXIO : 0);
310d58fda43Sjbeloro }
311d58fda43Sjbeloro
312d58fda43Sjbeloro /*ARGSUSED*/
313d58fda43Sjbeloro static int
epic_close(dev_t dev,int flag,int otyp,cred_t * credp)314d58fda43Sjbeloro epic_close(dev_t dev, int flag, int otyp, cred_t *credp)
315d58fda43Sjbeloro {
316d58fda43Sjbeloro _NOTE(ARGUNUSED(flag))
317d58fda43Sjbeloro _NOTE(ARGUNUSED(otyp))
318d58fda43Sjbeloro _NOTE(ARGUNUSED(credp))
319d58fda43Sjbeloro
320d58fda43Sjbeloro int inst = getminor(dev);
321d58fda43Sjbeloro
322d58fda43Sjbeloro return (getsoftc(inst) == NULL ? ENXIO : 0);
323d58fda43Sjbeloro }
324d58fda43Sjbeloro
325d58fda43Sjbeloro /*ARGSUSED*/
326d58fda43Sjbeloro static int
epic_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)327d58fda43Sjbeloro epic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
328d58fda43Sjbeloro int *rvalp)
329d58fda43Sjbeloro {
330d58fda43Sjbeloro _NOTE(ARGUNUSED(credp))
331d58fda43Sjbeloro
332d58fda43Sjbeloro int inst;
333d58fda43Sjbeloro struct epic_softc *softc;
334d58fda43Sjbeloro uint8_t in_command;
335d58fda43Sjbeloro
336d58fda43Sjbeloro inst = getminor(dev);
337d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL)
338d58fda43Sjbeloro return (ENXIO);
339d58fda43Sjbeloro
340d58fda43Sjbeloro mutex_enter(&softc->mutex);
341d58fda43Sjbeloro
342d58fda43Sjbeloro switch (cmd) {
343d58fda43Sjbeloro case EPIC_SET_POWER_LED:
344d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
345d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
346d58fda43Sjbeloro EPIC_POWER_LED_ON);
347d58fda43Sjbeloro break;
348d58fda43Sjbeloro case EPIC_RESET_POWER_LED:
349d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
350d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
351d58fda43Sjbeloro EPIC_POWER_LED_OFF);
352d58fda43Sjbeloro break;
353d58fda43Sjbeloro case EPIC_SB_BL_POWER_LED:
354d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
355d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
356d58fda43Sjbeloro EPIC_POWER_LED_SB_BLINK);
357d58fda43Sjbeloro break;
358d58fda43Sjbeloro case EPIC_FAST_BL_POWER_LED:
359d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
360d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
361d58fda43Sjbeloro EPIC_POWER_LED_FAST_BLINK);
362d58fda43Sjbeloro break;
363d58fda43Sjbeloro case EPIC_SET_ALERT_LED:
364d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
365d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
366d58fda43Sjbeloro EPIC_ALERT_LED_ON);
367d58fda43Sjbeloro break;
368d58fda43Sjbeloro case EPIC_RESET_ALERT_LED:
369d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
370d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
371d58fda43Sjbeloro EPIC_ALERT_LED_OFF);
372d58fda43Sjbeloro break;
373d58fda43Sjbeloro case EPIC_GET_FW:
374d58fda43Sjbeloro EPIC_READ(softc->cmd_handle, softc->cmd_reg,
375d58fda43Sjbeloro in_command, EPIC_IND_FW_VERSION);
376d58fda43Sjbeloro if (ddi_copyout((void *)(&in_command), (void *)arg,
377d58fda43Sjbeloro sizeof (in_command), mode) != DDI_SUCCESS) {
378d58fda43Sjbeloro mutex_exit(&softc->mutex);
379d58fda43Sjbeloro return (EFAULT);
380d58fda43Sjbeloro }
381d58fda43Sjbeloro break;
382d58fda43Sjbeloro default:
383d58fda43Sjbeloro mutex_exit(&softc->mutex);
384d58fda43Sjbeloro cmn_err(CE_WARN, "epic: cmd %d is not valid", cmd);
385d58fda43Sjbeloro return (EINVAL);
386d58fda43Sjbeloro }
387d58fda43Sjbeloro
388d58fda43Sjbeloro mutex_exit(&softc->mutex);
389d58fda43Sjbeloro return (0);
390d58fda43Sjbeloro }
391