1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Bus implementation for the NuBus subsystem.
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (C) 2017 Finn Thain
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/dma-mapping.h>
9*4882a593Smuzhiyun #include <linux/list.h>
10*4882a593Smuzhiyun #include <linux/nubus.h>
11*4882a593Smuzhiyun #include <linux/seq_file.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define to_nubus_board(d) container_of(d, struct nubus_board, dev)
15*4882a593Smuzhiyun #define to_nubus_driver(d) container_of(d, struct nubus_driver, driver)
16*4882a593Smuzhiyun
nubus_bus_match(struct device * dev,struct device_driver * driver)17*4882a593Smuzhiyun static int nubus_bus_match(struct device *dev, struct device_driver *driver)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun return 1;
20*4882a593Smuzhiyun }
21*4882a593Smuzhiyun
nubus_device_probe(struct device * dev)22*4882a593Smuzhiyun static int nubus_device_probe(struct device *dev)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun struct nubus_driver *ndrv = to_nubus_driver(dev->driver);
25*4882a593Smuzhiyun int err = -ENODEV;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun if (ndrv->probe)
28*4882a593Smuzhiyun err = ndrv->probe(to_nubus_board(dev));
29*4882a593Smuzhiyun return err;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
nubus_device_remove(struct device * dev)32*4882a593Smuzhiyun static int nubus_device_remove(struct device *dev)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct nubus_driver *ndrv = to_nubus_driver(dev->driver);
35*4882a593Smuzhiyun int err = -ENODEV;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun if (dev->driver && ndrv->remove)
38*4882a593Smuzhiyun err = ndrv->remove(to_nubus_board(dev));
39*4882a593Smuzhiyun return err;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct bus_type nubus_bus_type = {
43*4882a593Smuzhiyun .name = "nubus",
44*4882a593Smuzhiyun .match = nubus_bus_match,
45*4882a593Smuzhiyun .probe = nubus_device_probe,
46*4882a593Smuzhiyun .remove = nubus_device_remove,
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun EXPORT_SYMBOL(nubus_bus_type);
49*4882a593Smuzhiyun
nubus_driver_register(struct nubus_driver * ndrv)50*4882a593Smuzhiyun int nubus_driver_register(struct nubus_driver *ndrv)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun ndrv->driver.bus = &nubus_bus_type;
53*4882a593Smuzhiyun return driver_register(&ndrv->driver);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun EXPORT_SYMBOL(nubus_driver_register);
56*4882a593Smuzhiyun
nubus_driver_unregister(struct nubus_driver * ndrv)57*4882a593Smuzhiyun void nubus_driver_unregister(struct nubus_driver *ndrv)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun driver_unregister(&ndrv->driver);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun EXPORT_SYMBOL(nubus_driver_unregister);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static struct device nubus_parent = {
64*4882a593Smuzhiyun .init_name = "nubus",
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
nubus_bus_register(void)67*4882a593Smuzhiyun static int __init nubus_bus_register(void)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun return bus_register(&nubus_bus_type);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun postcore_initcall(nubus_bus_register);
72*4882a593Smuzhiyun
nubus_parent_device_register(void)73*4882a593Smuzhiyun int __init nubus_parent_device_register(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun return device_register(&nubus_parent);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
nubus_device_release(struct device * dev)78*4882a593Smuzhiyun static void nubus_device_release(struct device *dev)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun struct nubus_board *board = to_nubus_board(dev);
81*4882a593Smuzhiyun struct nubus_rsrc *fres, *tmp;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun list_for_each_entry_safe(fres, tmp, &nubus_func_rsrcs, list)
84*4882a593Smuzhiyun if (fres->board == board) {
85*4882a593Smuzhiyun list_del(&fres->list);
86*4882a593Smuzhiyun kfree(fres);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun kfree(board);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
nubus_device_register(struct nubus_board * board)91*4882a593Smuzhiyun int nubus_device_register(struct nubus_board *board)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun board->dev.parent = &nubus_parent;
94*4882a593Smuzhiyun board->dev.release = nubus_device_release;
95*4882a593Smuzhiyun board->dev.bus = &nubus_bus_type;
96*4882a593Smuzhiyun dev_set_name(&board->dev, "slot.%X", board->slot);
97*4882a593Smuzhiyun board->dev.dma_mask = &board->dev.coherent_dma_mask;
98*4882a593Smuzhiyun dma_set_mask(&board->dev, DMA_BIT_MASK(32));
99*4882a593Smuzhiyun return device_register(&board->dev);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
nubus_print_device_name_fn(struct device * dev,void * data)102*4882a593Smuzhiyun static int nubus_print_device_name_fn(struct device *dev, void *data)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun struct nubus_board *board = to_nubus_board(dev);
105*4882a593Smuzhiyun struct seq_file *m = data;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun seq_printf(m, "Slot %X: %s\n", board->slot, board->name);
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
nubus_proc_show(struct seq_file * m,void * data)111*4882a593Smuzhiyun int nubus_proc_show(struct seq_file *m, void *data)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun return bus_for_each_dev(&nubus_bus_type, NULL, m,
114*4882a593Smuzhiyun nubus_print_device_name_fn);
115*4882a593Smuzhiyun }
116