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