1/*
2 * Copyright (C) 2012 CERN (www.cern.ch)
3 * Author: Alessandro Rubini <rubini@gnudd.com>
4 *
5 * Released according to the GNU GPL, version 2 or any later version.
6 *
7 * This work is part of the White Rabbit project, a research effort led
8 * by CERN, the European Institute for Nuclear Research.
9 */
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/device.h>
15#include <linux/fmc.h>
16
17static int fmc_check_version(unsigned long version, const char *name)
18{
19	if (__FMC_MAJOR(version) != FMC_MAJOR) {
20		pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n",
21		       __func__, name, __FMC_MAJOR(version), FMC_MAJOR);
22		return -EINVAL;
23	}
24
25	if (__FMC_MINOR(version) != FMC_MINOR)
26		pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n",
27		       __func__, name, __FMC_MINOR(version), FMC_MINOR);
28	return 0;
29}
30
31static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env)
32{
33	/* struct fmc_device *fdev = to_fmc_device(dev); */
34
35	/* FIXME: The MODALIAS */
36	add_uevent_var(env, "MODALIAS=%s", "fmc");
37	return 0;
38}
39
40static int fmc_probe(struct device *dev)
41{
42	struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
43	struct fmc_device *fdev = to_fmc_device(dev);
44
45	return fdrv->probe(fdev);
46}
47
48static int fmc_remove(struct device *dev)
49{
50	struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
51	struct fmc_device *fdev = to_fmc_device(dev);
52
53	return fdrv->remove(fdev);
54}
55
56static void fmc_shutdown(struct device *dev)
57{
58	/* not implemented but mandatory */
59}
60
61static struct bus_type fmc_bus_type = {
62	.name = "fmc",
63	.match = fmc_match,
64	.uevent = fmc_uevent,
65	.probe = fmc_probe,
66	.remove = fmc_remove,
67	.shutdown = fmc_shutdown,
68};
69
70static void fmc_release(struct device *dev)
71{
72	struct fmc_device *fmc = container_of(dev, struct fmc_device, dev);
73
74	kfree(fmc);
75}
76
77/*
78 * The eeprom is exported in sysfs, through a binary attribute
79 */
80
81static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
82			   struct bin_attribute *bin_attr,
83			   char *buf, loff_t off, size_t count)
84{
85	struct device *dev;
86	struct fmc_device *fmc;
87	int eelen;
88
89	dev = container_of(kobj, struct device, kobj);
90	fmc = container_of(dev, struct fmc_device, dev);
91	eelen = fmc->eeprom_len;
92	if (off > eelen)
93		return -ESPIPE;
94	if (off == eelen)
95		return 0; /* EOF */
96	if (off + count > eelen)
97		count = eelen - off;
98	memcpy(buf, fmc->eeprom + off, count);
99	return count;
100}
101
102static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
103				struct bin_attribute *bin_attr,
104				char *buf, loff_t off, size_t count)
105{
106	struct device *dev;
107	struct fmc_device *fmc;
108
109	dev = container_of(kobj, struct device, kobj);
110	fmc = container_of(dev, struct fmc_device, dev);
111	return fmc->op->write_ee(fmc, off, buf, count);
112}
113
114static struct bin_attribute fmc_eeprom_attr = {
115	.attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
116	.size = 8192, /* more or less standard */
117	.read = fmc_read_eeprom,
118	.write = fmc_write_eeprom,
119};
120
121/*
122 * Functions for client modules follow
123 */
124
125int fmc_driver_register(struct fmc_driver *drv)
126{
127	if (fmc_check_version(drv->version, drv->driver.name))
128		return -EINVAL;
129	drv->driver.bus = &fmc_bus_type;
130	return driver_register(&drv->driver);
131}
132EXPORT_SYMBOL(fmc_driver_register);
133
134void fmc_driver_unregister(struct fmc_driver *drv)
135{
136	driver_unregister(&drv->driver);
137}
138EXPORT_SYMBOL(fmc_driver_unregister);
139
140/*
141 * When a device set is registered, all eeproms must be read
142 * and all FRUs must be parsed
143 */
144int fmc_device_register_n(struct fmc_device **devs, int n)
145{
146	struct fmc_device *fmc, **devarray;
147	uint32_t device_id;
148	int i, ret = 0;
149
150	if (n < 1)
151		return 0;
152
153	/* Check the version of the first data structure (function prints) */
154	if (fmc_check_version(devs[0]->version, devs[0]->carrier_name))
155		return -EINVAL;
156
157	devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL);
158	if (!devarray)
159		return -ENOMEM;
160
161	/* Make all other checks before continuing, for all devices */
162	for (i = 0; i < n; i++) {
163		fmc = devarray[i];
164		if (!fmc->hwdev) {
165			pr_err("%s: device nr. %i has no hwdev pointer\n",
166			       __func__, i);
167			ret = -EINVAL;
168			break;
169		}
170		if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
171			dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
172				 fmc->slot_id);
173			continue;
174		}
175		if (!fmc->eeprom) {
176			dev_err(fmc->hwdev, "no eeprom provided for slot %i\n",
177				fmc->slot_id);
178			ret = -EINVAL;
179		}
180		if (!fmc->eeprom_addr) {
181			dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n",
182				fmc->slot_id);
183			ret = -EINVAL;
184		}
185		if (!fmc->carrier_name || !fmc->carrier_data ||
186		    !fmc->device_id) {
187			dev_err(fmc->hwdev,
188				"deivce nr %i: carrier name, "
189				"data or dev_id not set\n", i);
190			ret = -EINVAL;
191		}
192		if (ret)
193			break;
194
195	}
196	if (ret) {
197		kfree(devarray);
198		return ret;
199	}
200
201	/* Validation is ok. Now init and register the devices */
202	for (i = 0; i < n; i++) {
203		fmc = devarray[i];
204
205		fmc->nr_slots = n; /* each slot must know how many are there */
206		fmc->devarray = devarray;
207
208		device_initialize(&fmc->dev);
209		fmc->dev.release = fmc_release;
210		fmc->dev.parent = fmc->hwdev;
211
212		/* Fill the identification stuff (may fail) */
213		fmc_fill_id_info(fmc);
214
215		fmc->dev.bus = &fmc_bus_type;
216
217		/* Name from mezzanine info or carrier info. Or 0,1,2.. */
218		device_id = fmc->device_id;
219		if (!fmc->mezzanine_name)
220			dev_set_name(&fmc->dev, "fmc-%04x", device_id);
221		else
222			dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name,
223				     device_id);
224		ret = device_add(&fmc->dev);
225		if (ret < 0) {
226			dev_err(fmc->hwdev, "Slot %i: Failed in registering "
227				"\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name);
228			goto out;
229		}
230		ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr);
231		if (ret < 0) {
232			dev_err(&fmc->dev, "Failed in registering eeprom\n");
233			goto out1;
234		}
235		/* This device went well, give information to the user */
236		fmc_dump_eeprom(fmc);
237		fmc_dump_sdb(fmc);
238	}
239	return 0;
240
241out1:
242	device_del(&fmc->dev);
243out:
244	fmc_free_id_info(fmc);
245	put_device(&fmc->dev);
246
247	kfree(devarray);
248	for (i--; i >= 0; i--) {
249		sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
250		device_del(&devs[i]->dev);
251		fmc_free_id_info(devs[i]);
252		put_device(&devs[i]->dev);
253	}
254	return ret;
255
256}
257EXPORT_SYMBOL(fmc_device_register_n);
258
259int fmc_device_register(struct fmc_device *fmc)
260{
261	return fmc_device_register_n(&fmc, 1);
262}
263EXPORT_SYMBOL(fmc_device_register);
264
265void fmc_device_unregister_n(struct fmc_device **devs, int n)
266{
267	int i;
268
269	if (n < 1)
270		return;
271
272	/* Free devarray first, not used by the later loop */
273	kfree(devs[0]->devarray);
274
275	for (i = 0; i < n; i++) {
276		sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
277		device_del(&devs[i]->dev);
278		fmc_free_id_info(devs[i]);
279		put_device(&devs[i]->dev);
280	}
281}
282EXPORT_SYMBOL(fmc_device_unregister_n);
283
284void fmc_device_unregister(struct fmc_device *fmc)
285{
286	fmc_device_unregister_n(&fmc, 1);
287}
288EXPORT_SYMBOL(fmc_device_unregister);
289
290/* Init and exit are trivial */
291static int fmc_init(void)
292{
293	return bus_register(&fmc_bus_type);
294}
295
296static void fmc_exit(void)
297{
298	bus_unregister(&fmc_bus_type);
299}
300
301module_init(fmc_init);
302module_exit(fmc_exit);
303
304MODULE_LICENSE("GPL");
305