1235288Sadrian/*-
2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke.
3235288Sadrian * All rights reserved.
4235288Sadrian *
5235288Sadrian * Redistribution and use in source and binary forms, with or without
6235288Sadrian * modification, are permitted provided that the following conditions
7235288Sadrian * are met:
8235288Sadrian * 1. Redistributions of source code must retain the above copyright
9235288Sadrian *    notice, this list of conditions and the following disclaimer.
10235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11235288Sadrian *    notice, this list of conditions and the following disclaimer in the
12235288Sadrian *    documentation and/or other materials provided with the distribution.
13235288Sadrian *
14235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235288Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235288Sadrian * SUCH DAMAGE.
25235288Sadrian *
26235288Sadrian * $FreeBSD: releng/10.3/sys/dev/etherswitch/etherswitch.c 250381 2013-05-08 20:46:54Z adrian $
27235288Sadrian */
28235288Sadrian
29235288Sadrian#include <sys/param.h>
30235288Sadrian#include <sys/bus.h>
31235288Sadrian#include <sys/conf.h>
32235288Sadrian#include <sys/fcntl.h>
33235288Sadrian#include <sys/lock.h>
34235288Sadrian#include <sys/kernel.h>
35235288Sadrian#include <sys/malloc.h>
36235288Sadrian#include <sys/module.h>
37235288Sadrian#include <sys/socket.h>
38235288Sadrian#include <sys/sx.h>
39235288Sadrian#include <sys/systm.h>
40235288Sadrian#include <sys/uio.h>
41235288Sadrian
42235288Sadrian#include <net/if.h>
43235288Sadrian
44235288Sadrian#include <dev/etherswitch/etherswitch.h>
45235288Sadrian
46235288Sadrian#include "etherswitch_if.h"
47235288Sadrian
48235288Sadrian#define BUFSIZE 1024
49235288Sadrian
50235288Sadrianstruct etherswitch_softc {
51235288Sadrian	device_t sc_dev;
52235288Sadrian	int sc_count;
53235288Sadrian
54235288Sadrian	struct cdev *sc_devnode;
55235288Sadrian	struct sx sc_lock;
56235288Sadrian};
57235288Sadrian
58235288Sadrian#define	SWITCH_LOCK(sc)			sx_xlock(&(sc)->sc_lock)
59235288Sadrian#define	SWITCH_UNLOCK(sc)			sx_xunlock(&(sc)->sc_lock)
60235288Sadrian
61235288Sadrianstatic int etherswitch_probe(device_t);
62235288Sadrianstatic int etherswitch_attach(device_t);
63235288Sadrianstatic int etherswitch_detach(device_t);
64235288Sadrianstatic void etherswitch_identify(driver_t *driver, device_t parent);
65235288Sadrian
66235288Sadriandevclass_t etherswitch_devclass;
67235288Sadrian
68235288Sadrianstatic device_method_t etherswitch_methods[] = {
69235288Sadrian	/* device interface */
70235288Sadrian	DEVMETHOD(device_identify,	etherswitch_identify),
71235288Sadrian	DEVMETHOD(device_probe,		etherswitch_probe),
72235288Sadrian	DEVMETHOD(device_attach,	etherswitch_attach),
73235288Sadrian	DEVMETHOD(device_detach,	etherswitch_detach),
74235288Sadrian
75235288Sadrian	{ 0, 0 }
76235288Sadrian};
77235288Sadrian
78235288Sadriandriver_t etherswitch_driver = {
79235288Sadrian	"etherswitch",
80235288Sadrian	etherswitch_methods,
81235288Sadrian	sizeof(struct etherswitch_softc),
82235288Sadrian};
83235288Sadrian
84235288Sadrianstatic	d_open_t	etherswitchopen;
85235288Sadrianstatic	d_close_t	etherswitchclose;
86235288Sadrianstatic	d_write_t	etherswitchwrite;
87235288Sadrianstatic	d_read_t	etherswitchread;
88235288Sadrianstatic	d_ioctl_t	etherswitchioctl;
89235288Sadrian
90235288Sadrianstatic struct cdevsw etherswitch_cdevsw = {
91235288Sadrian	.d_version =	D_VERSION,
92235288Sadrian	.d_flags =	D_TRACKCLOSE,
93235288Sadrian	.d_open =	etherswitchopen,
94235288Sadrian	.d_close =	etherswitchclose,
95235288Sadrian	.d_read =	etherswitchread,
96235288Sadrian	.d_write =	etherswitchwrite,
97235288Sadrian	.d_ioctl =	etherswitchioctl,
98235288Sadrian	.d_name =	"etherswitch",
99235288Sadrian};
100235288Sadrian
101235288Sadrianstatic void
102235288Sadrianetherswitch_identify(driver_t *driver, device_t parent)
103235288Sadrian{
104235288Sadrian	if (device_find_child(parent, "etherswitch", -1) == NULL)
105235288Sadrian		BUS_ADD_CHILD(parent, 0, "etherswitch", -1);
106235288Sadrian}
107235288Sadrian
108235288Sadrianstatic int
109235288Sadrianetherswitch_probe(device_t dev)
110235288Sadrian{
111235288Sadrian	device_set_desc(dev, "Switch controller");
112235288Sadrian
113235288Sadrian	return (0);
114235288Sadrian}
115235288Sadrian
116235288Sadrianstatic int
117235288Sadrianetherswitch_attach(device_t dev)
118235288Sadrian{
119235288Sadrian	struct etherswitch_softc *sc = (struct etherswitch_softc *)device_get_softc(dev);
120235288Sadrian
121235288Sadrian	sc->sc_dev = dev;
122235288Sadrian	sx_init(&sc->sc_lock, "etherswitch");
123235288Sadrian	sc->sc_devnode = make_dev(&etherswitch_cdevsw, device_get_unit(dev),
124235288Sadrian			UID_ROOT, GID_WHEEL,
125235288Sadrian			0600, "etherswitch%d", device_get_unit(dev));
126235288Sadrian	if (sc->sc_devnode == NULL) {
127235288Sadrian		device_printf(dev, "failed to create character device\n");
128235288Sadrian		sx_destroy(&sc->sc_lock);
129235288Sadrian		return (ENXIO);
130235288Sadrian	}
131235288Sadrian	sc->sc_devnode->si_drv1 = sc;
132235288Sadrian
133235288Sadrian	return (0);
134235288Sadrian}
135235288Sadrian
136235288Sadrianstatic int
137235288Sadrianetherswitch_detach(device_t dev)
138235288Sadrian{
139235288Sadrian	struct etherswitch_softc *sc = (struct etherswitch_softc *)device_get_softc(dev);
140235288Sadrian
141235288Sadrian	if (sc->sc_devnode)
142235288Sadrian		destroy_dev(sc->sc_devnode);
143235288Sadrian	sx_destroy(&sc->sc_lock);
144235288Sadrian
145235288Sadrian	return (0);
146235288Sadrian}
147235288Sadrian
148235288Sadrianstatic int
149235288Sadrianetherswitchopen(struct cdev *dev, int flags, int fmt, struct thread *td)
150235288Sadrian{
151235288Sadrian	struct etherswitch_softc *sc = dev->si_drv1;
152235288Sadrian
153235288Sadrian	SWITCH_LOCK(sc);
154235288Sadrian	if (sc->sc_count > 0) {
155235288Sadrian		SWITCH_UNLOCK(sc);
156235288Sadrian		return (EBUSY);
157235288Sadrian	}
158235288Sadrian
159235288Sadrian	sc->sc_count++;
160235288Sadrian	SWITCH_UNLOCK(sc);
161235288Sadrian
162235288Sadrian	return (0);
163235288Sadrian}
164235288Sadrian
165235288Sadrianstatic int
166235288Sadrianetherswitchclose(struct cdev *dev, int flags, int fmt, struct thread *td)
167235288Sadrian{
168235288Sadrian	struct etherswitch_softc *sc = dev->si_drv1;
169235288Sadrian
170235288Sadrian	SWITCH_LOCK(sc);
171235288Sadrian	if (sc->sc_count == 0) {
172235288Sadrian		SWITCH_UNLOCK(sc);
173235288Sadrian		return (EINVAL);
174235288Sadrian	}
175235288Sadrian
176235288Sadrian	sc->sc_count--;
177235288Sadrian
178235288Sadrian	if (sc->sc_count < 0)
179235288Sadrian		panic("%s: etherswitch_count < 0!", __func__);
180235288Sadrian	SWITCH_UNLOCK(sc);
181235288Sadrian
182235288Sadrian	return (0);
183235288Sadrian}
184235288Sadrian
185235288Sadrianstatic int
186235288Sadrianetherswitchwrite(struct cdev *dev, struct uio * uio, int ioflag)
187235288Sadrian{
188235288Sadrian	return (EINVAL);
189235288Sadrian}
190235288Sadrian
191235288Sadrianstatic int
192235288Sadrianetherswitchread(struct cdev *dev, struct uio * uio, int ioflag)
193235288Sadrian{
194235288Sadrian	return (EINVAL);
195235288Sadrian}
196235288Sadrian
197235288Sadrianstatic int
198235288Sadrianetherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct thread *td)
199235288Sadrian{
200235288Sadrian	struct etherswitch_softc *sc = cdev->si_drv1;
201235288Sadrian	device_t dev = sc->sc_dev;
202235288Sadrian	device_t etherswitch = device_get_parent(dev);
203250381Sadrian	etherswitch_conf_t conf;
204235288Sadrian	etherswitch_info_t *info;
205235288Sadrian	etherswitch_reg_t *reg;
206235288Sadrian	etherswitch_phyreg_t *phyreg;
207235288Sadrian	int error = 0;
208235288Sadrian
209235288Sadrian	switch (cmd) {
210235288Sadrian	case IOETHERSWITCHGETINFO:
211235288Sadrian		info = ETHERSWITCH_GETINFO(etherswitch);
212235288Sadrian		bcopy(info, data, sizeof(etherswitch_info_t));
213235288Sadrian		break;
214235288Sadrian
215235288Sadrian	case IOETHERSWITCHGETREG:
216235288Sadrian		reg = (etherswitch_reg_t *)data;
217241578Sray		ETHERSWITCH_LOCK(etherswitch);
218235288Sadrian		reg->val = ETHERSWITCH_READREG(etherswitch, reg->reg);
219241578Sray		ETHERSWITCH_UNLOCK(etherswitch);
220235288Sadrian		break;
221235288Sadrian
222235288Sadrian	case IOETHERSWITCHSETREG:
223235288Sadrian		reg = (etherswitch_reg_t *)data;
224241578Sray		ETHERSWITCH_LOCK(etherswitch);
225235288Sadrian		error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val);
226241578Sray		ETHERSWITCH_UNLOCK(etherswitch);
227235288Sadrian		break;
228235288Sadrian
229235288Sadrian	case IOETHERSWITCHGETPORT:
230235288Sadrian		error = ETHERSWITCH_GETPORT(etherswitch, (etherswitch_port_t *)data);
231235288Sadrian		break;
232235288Sadrian
233235288Sadrian	case IOETHERSWITCHSETPORT:
234235288Sadrian		error = ETHERSWITCH_SETPORT(etherswitch, (etherswitch_port_t *)data);
235235288Sadrian		break;
236235288Sadrian
237235288Sadrian	case IOETHERSWITCHGETVLANGROUP:
238235288Sadrian		error = ETHERSWITCH_GETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data);
239235288Sadrian		break;
240235288Sadrian
241235288Sadrian	case IOETHERSWITCHSETVLANGROUP:
242235288Sadrian		error = ETHERSWITCH_SETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data);
243235288Sadrian		break;
244235288Sadrian
245235288Sadrian	case IOETHERSWITCHGETPHYREG:
246235288Sadrian		phyreg = (etherswitch_phyreg_t *)data;
247235288Sadrian		phyreg->val = ETHERSWITCH_READPHYREG(etherswitch, phyreg->phy, phyreg->reg);
248235288Sadrian		break;
249235288Sadrian
250235288Sadrian	case IOETHERSWITCHSETPHYREG:
251235288Sadrian		phyreg = (etherswitch_phyreg_t *)data;
252235288Sadrian		error = ETHERSWITCH_WRITEPHYREG(etherswitch, phyreg->phy, phyreg->reg, phyreg->val);
253235288Sadrian		break;
254235288Sadrian
255250381Sadrian	case IOETHERSWITCHGETCONF:
256250381Sadrian		bzero(&conf, sizeof(etherswitch_conf_t));
257250381Sadrian		error = ETHERSWITCH_GETCONF(etherswitch, &conf);
258250381Sadrian		bcopy(&conf, data, sizeof(etherswitch_conf_t));
259250381Sadrian		break;
260250381Sadrian
261250381Sadrian	case IOETHERSWITCHSETCONF:
262250381Sadrian		error = ETHERSWITCH_SETCONF(etherswitch, (etherswitch_conf_t *)data);
263250381Sadrian		break;
264250381Sadrian
265235288Sadrian	default:
266235288Sadrian		error = ENOTTY;
267235288Sadrian	}
268235288Sadrian
269235288Sadrian	return (error);
270235288Sadrian}
271235288Sadrian
272235288SadrianMODULE_VERSION(etherswitch, 1);
273