Loading...
Note: File does not exist in v6.8.
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * PCI Hot Plug Controller Skeleton Driver - 0.3
4 *
5 * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001,2003 IBM Corp.
7 *
8 * All rights reserved.
9 *
10 * This driver is to be used as a skeleton driver to show how to interface
11 * with the pci hotplug core easily.
12 *
13 * Send feedback to <greg@kroah.com>
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/kernel.h>
20#include <linux/slab.h>
21#include <linux/pci.h>
22#include <linux/pci_hotplug.h>
23#include <linux/init.h>
24
25#define SLOT_NAME_SIZE 10
26struct slot {
27 u8 number;
28 struct hotplug_slot *hotplug_slot;
29 struct list_head slot_list;
30 char name[SLOT_NAME_SIZE];
31};
32
33static LIST_HEAD(slot_list);
34
35#define MY_NAME "pcihp_skeleton"
36
37#define dbg(format, arg...) \
38 do { \
39 if (debug) \
40 printk(KERN_DEBUG "%s: " format "\n", \
41 MY_NAME, ## arg); \
42 } while (0)
43#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
44#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
45#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
46
47/* local variables */
48static bool debug;
49static int num_slots;
50
51#define DRIVER_VERSION "0.3"
52#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
53#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver"
54
55MODULE_AUTHOR(DRIVER_AUTHOR);
56MODULE_DESCRIPTION(DRIVER_DESC);
57MODULE_LICENSE("GPL");
58module_param(debug, bool, 0644);
59MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
60
61static int enable_slot(struct hotplug_slot *slot);
62static int disable_slot(struct hotplug_slot *slot);
63static int set_attention_status(struct hotplug_slot *slot, u8 value);
64static int hardware_test(struct hotplug_slot *slot, u32 value);
65static int get_power_status(struct hotplug_slot *slot, u8 *value);
66static int get_attention_status(struct hotplug_slot *slot, u8 *value);
67static int get_latch_status(struct hotplug_slot *slot, u8 *value);
68static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
69
70static struct hotplug_slot_ops skel_hotplug_slot_ops = {
71 .enable_slot = enable_slot,
72 .disable_slot = disable_slot,
73 .set_attention_status = set_attention_status,
74 .hardware_test = hardware_test,
75 .get_power_status = get_power_status,
76 .get_attention_status = get_attention_status,
77 .get_latch_status = get_latch_status,
78 .get_adapter_status = get_adapter_status,
79};
80
81static int enable_slot(struct hotplug_slot *hotplug_slot)
82{
83 struct slot *slot = hotplug_slot->private;
84 int retval = 0;
85
86 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
87
88 /*
89 * Fill in code here to enable the specified slot
90 */
91
92 return retval;
93}
94
95static int disable_slot(struct hotplug_slot *hotplug_slot)
96{
97 struct slot *slot = hotplug_slot->private;
98 int retval = 0;
99
100 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
101
102 /*
103 * Fill in code here to disable the specified slot
104 */
105
106 return retval;
107}
108
109static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
110{
111 struct slot *slot = hotplug_slot->private;
112 int retval = 0;
113
114 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
115
116 switch (status) {
117 case 0:
118 /*
119 * Fill in code here to turn light off
120 */
121 break;
122
123 case 1:
124 default:
125 /*
126 * Fill in code here to turn light on
127 */
128 break;
129 }
130
131 return retval;
132}
133
134static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
135{
136 struct slot *slot = hotplug_slot->private;
137 int retval = 0;
138
139 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
140
141 switch (value) {
142 case 0:
143 /* Specify a test here */
144 break;
145 case 1:
146 /* Specify another test here */
147 break;
148 }
149
150 return retval;
151}
152
153static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
154{
155 struct slot *slot = hotplug_slot->private;
156 int retval = 0;
157
158 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
159
160 /*
161 * Fill in logic to get the current power status of the specific
162 * slot and store it in the *value location.
163 */
164
165 return retval;
166}
167
168static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
169{
170 struct slot *slot = hotplug_slot->private;
171 int retval = 0;
172
173 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
174
175 /*
176 * Fill in logic to get the current attention status of the specific
177 * slot and store it in the *value location.
178 */
179
180 return retval;
181}
182
183static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
184{
185 struct slot *slot = hotplug_slot->private;
186 int retval = 0;
187
188 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
189
190 /*
191 * Fill in logic to get the current latch status of the specific
192 * slot and store it in the *value location.
193 */
194
195 return retval;
196}
197
198static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
199{
200 struct slot *slot = hotplug_slot->private;
201 int retval = 0;
202
203 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
204
205 /*
206 * Fill in logic to get the current adapter status of the specific
207 * slot and store it in the *value location.
208 */
209
210 return retval;
211}
212
213static void release_slot(struct hotplug_slot *hotplug_slot)
214{
215 struct slot *slot = hotplug_slot->private;
216
217 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
218 kfree(slot->hotplug_slot->info);
219 kfree(slot->hotplug_slot);
220 kfree(slot);
221}
222
223static void make_slot_name(struct slot *slot)
224{
225 /*
226 * Stupid way to make a filename out of the slot name.
227 * replace this if your hardware provides a better way to name slots.
228 */
229 snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number);
230}
231
232/**
233 * init_slots - initialize 'struct slot' structures for each slot
234 *
235 */
236static int __init init_slots(void)
237{
238 struct slot *slot;
239 struct hotplug_slot *hotplug_slot;
240 struct hotplug_slot_info *info;
241 int retval;
242 int i;
243
244 /*
245 * Create a structure for each slot, and register that slot
246 * with the pci_hotplug subsystem.
247 */
248 for (i = 0; i < num_slots; ++i) {
249 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
250 if (!slot) {
251 retval = -ENOMEM;
252 goto error;
253 }
254
255 hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
256 if (!hotplug_slot) {
257 retval = -ENOMEM;
258 goto error_slot;
259 }
260 slot->hotplug_slot = hotplug_slot;
261
262 info = kzalloc(sizeof(*info), GFP_KERNEL);
263 if (!info) {
264 retval = -ENOMEM;
265 goto error_hpslot;
266 }
267 hotplug_slot->info = info;
268
269 slot->number = i;
270
271 hotplug_slot->name = slot->name;
272 hotplug_slot->private = slot;
273 hotplug_slot->release = &release_slot;
274 make_slot_name(slot);
275 hotplug_slot->ops = &skel_hotplug_slot_ops;
276
277 /*
278 * Initialize the slot info structure with some known
279 * good values.
280 */
281 get_power_status(hotplug_slot, &info->power_status);
282 get_attention_status(hotplug_slot, &info->attention_status);
283 get_latch_status(hotplug_slot, &info->latch_status);
284 get_adapter_status(hotplug_slot, &info->adapter_status);
285
286 dbg("registering slot %d\n", i);
287 retval = pci_hp_register(slot->hotplug_slot);
288 if (retval) {
289 err("pci_hp_register failed with error %d\n", retval);
290 goto error_info;
291 }
292
293 /* add slot to our internal list */
294 list_add(&slot->slot_list, &slot_list);
295 }
296
297 return 0;
298error_info:
299 kfree(info);
300error_hpslot:
301 kfree(hotplug_slot);
302error_slot:
303 kfree(slot);
304error:
305 return retval;
306}
307
308static void __exit cleanup_slots(void)
309{
310 struct slot *slot, *next;
311
312 /*
313 * Unregister all of our slots with the pci_hotplug subsystem.
314 * Memory will be freed in release_slot() callback after slot's
315 * lifespan is finished.
316 */
317 list_for_each_entry_safe(slot, next, &slot_list, slot_list) {
318 list_del(&slot->slot_list);
319 pci_hp_deregister(slot->hotplug_slot);
320 }
321}
322
323static int __init pcihp_skel_init(void)
324{
325 int retval;
326
327 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
328 /*
329 * Do specific initialization stuff for your driver here
330 * like initializing your controller hardware (if any) and
331 * determining the number of slots you have in the system
332 * right now.
333 */
334 num_slots = 5;
335
336 return init_slots();
337}
338
339static void __exit pcihp_skel_exit(void)
340{
341 /*
342 * Clean everything up.
343 */
344 cleanup_slots();
345}
346
347module_init(pcihp_skel_init);
348module_exit(pcihp_skel_exit);