blob: 699007d9ba277b5f8555113654837055dd7e5bb4 [file] [log] [blame]
Angel Ponsc74dae92020-04-02 23:48:16 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Eric Biederman5cd81732004-03-11 15:01:31 +00002
3#include <console/console.h>
Eric Biederman5cd81732004-03-11 15:01:31 +00004#include <stdint.h>
Eric Biederman5cd81732004-03-11 15:01:31 +00005#include <arch/io.h>
6#include <device/device.h>
7#include <device/pnp.h>
8
Nico Huberdd4715b2013-06-10 22:08:35 +02009/* PNP config mode wrappers */
10
Elyes HAOUASb77cf622018-05-02 21:01:18 +020011void pnp_enter_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020012{
13 if (dev->ops->ops_pnp_mode)
14 dev->ops->ops_pnp_mode->enter_conf_mode(dev);
15}
16
Elyes HAOUASb77cf622018-05-02 21:01:18 +020017void pnp_exit_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020018{
19 if (dev->ops->ops_pnp_mode)
20 dev->ops->ops_pnp_mode->exit_conf_mode(dev);
21}
22
Patrick Rudolph7db16dd2019-12-10 13:15:42 +010023#if CONFIG(HAVE_ACPI_TABLES)
24void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data)
25{
26 if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_enter_conf_mode)
27 dev->ops->ops_pnp_mode->ssdt_enter_conf_mode(dev, idx, data);
28}
29void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data)
30{
31 if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_exit_conf_mode)
32 dev->ops->ops_pnp_mode->ssdt_exit_conf_mode(dev, idx, data);
33}
34#endif
35
Eric Biederman5cd81732004-03-11 15:01:31 +000036/* PNP fundamental operations */
37
Elyes HAOUASb77cf622018-05-02 21:01:18 +020038void pnp_write_config(struct device *dev, u8 reg, u8 value)
Eric Biederman5cd81732004-03-11 15:01:31 +000039{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000040 outb(reg, dev->path.pnp.port);
41 outb(value, dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000042}
43
Elyes HAOUASb77cf622018-05-02 21:01:18 +020044u8 pnp_read_config(struct device *dev, u8 reg)
Eric Biederman5cd81732004-03-11 15:01:31 +000045{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000046 outb(reg, dev->path.pnp.port);
47 return inb(dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000048}
49
Angel Ponsbb8d00d2021-06-06 19:20:48 +020050void pnp_unset_and_set_config(struct device *dev, u8 reg, u8 unset, u8 set)
51{
52 outb(reg, dev->path.pnp.port);
53 u8 value = inb(dev->path.pnp.port + 1);
54 value &= ~unset;
55 value |= set;
56 outb(value, dev->path.pnp.port + 1);
57}
58
Elyes HAOUASb77cf622018-05-02 21:01:18 +020059void pnp_set_logical_device(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000060{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000061 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
Eric Biederman5cd81732004-03-11 15:01:31 +000062}
63
Elyes HAOUASb77cf622018-05-02 21:01:18 +020064void pnp_set_enable(struct device *dev, int enable)
Eric Biederman5cd81732004-03-11 15:01:31 +000065{
Uwe Hermannd453dd02010-10-18 00:00:57 +000066 u8 tmp, bitpos;
Rudolf Marek623df672008-02-18 20:32:46 +000067
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020068 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000069
70 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000071 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Rudolf Marek623df672008-02-18 20:32:46 +000072
Uwe Hermannd453dd02010-10-18 00:00:57 +000073 if (enable)
Rudolf Marek623df672008-02-18 20:32:46 +000074 tmp |= (1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000075 else
Rudolf Marek623df672008-02-18 20:32:46 +000076 tmp &= ~(1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000077
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020078 pnp_write_config(dev, PNP_IDX_EN, tmp);
Eric Biederman5cd81732004-03-11 15:01:31 +000079}
80
Elyes HAOUASb77cf622018-05-02 21:01:18 +020081int pnp_read_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000082{
Uwe Hermannd453dd02010-10-18 00:00:57 +000083 u8 tmp, bitpos;
84
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020085 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000086
87 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000088 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Uwe Hermannd453dd02010-10-18 00:00:57 +000089
Rudolf Marekb05d4bb2008-02-19 20:30:25 +000090 return !!(tmp & (1 << bitpos));
Eric Biederman5cd81732004-03-11 15:01:31 +000091}
92
Elyes HAOUASb77cf622018-05-02 21:01:18 +020093void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
Eric Biederman5cd81732004-03-11 15:01:31 +000094{
Uwe Hermannd453dd02010-10-18 00:00:57 +000095 /* Index == 0x60 or 0x62. */
Eric Biederman5cd81732004-03-11 15:01:31 +000096 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
97 pnp_write_config(dev, index + 1, iobase & 0xff);
98}
99
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200100void pnp_set_irq(struct device *dev, u8 index, u8 irq)
Eric Biederman5cd81732004-03-11 15:01:31 +0000101{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000102 /* Index == 0x70 or 0x72. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000103 pnp_write_config(dev, index, irq);
104}
105
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200106void pnp_set_drq(struct device *dev, u8 index, u8 drq)
Eric Biederman5cd81732004-03-11 15:01:31 +0000107{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000108 /* Index == 0x74. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000109 pnp_write_config(dev, index, drq & 0xff);
110}
111
112/* PNP device operations */
113
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200114void pnp_read_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000115{
116 return;
117}
118
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200119static void pnp_set_resource(struct device *dev, struct resource *resource)
Eric Biederman5cd81732004-03-11 15:01:31 +0000120{
121 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Elyes HAOUAS495bb662019-09-23 13:15:41 +0200122 /* The PNP_MSC Super IO registers have the IRQ flag set. If no
Felix Helda6627772018-07-27 16:41:32 +0200123 value is assigned in the devicetree, the corresponding
124 PNP_MSC register doesn't get written, which should be printed
125 as warning and not as error. */
126 if (resource->flags & IORESOURCE_IRQ &&
127 (resource->index != PNP_IDX_IRQ0) &&
128 (resource->index != PNP_IDX_IRQ1))
129 printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
Felix Held24d0ed72020-01-30 19:52:23 +0100130 "0x%010llx not assigned in devicetree\n", dev_path(dev),
Felix Helda6627772018-07-27 16:41:32 +0200131 resource->index, resource_type(resource),
132 resource->size);
133 else
134 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
Felix Held24d0ed72020-01-30 19:52:23 +0100135 "not assigned in devicetree\n", dev_path(dev), resource->index,
Felix Helda6627772018-07-27 16:41:32 +0200136 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000137 return;
138 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000139
Uwe Hermannd453dd02010-10-18 00:00:57 +0000140 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000141 if (resource->flags & IORESOURCE_IO) {
142 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000143 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000144 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000145 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000146 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000147 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000148 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000149 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000150 return;
151 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000152 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000153
Eric Biederman03acab62004-10-14 21:25:53 +0000154 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000155}
156
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200157void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000158{
Myles Watsonc25cc112010-05-21 14:33:48 +0000159 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000160
Nico Huberdd4715b2013-06-10 22:08:35 +0200161 pnp_enter_conf_mode(dev);
162
Uwe Hermannd453dd02010-10-18 00:00:57 +0000163 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000164 pnp_set_logical_device(dev);
165
166 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000167 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000168 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200169
170 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000171}
172
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200173void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000174{
Nico Huberdd4715b2013-06-10 22:08:35 +0200175 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000176 pnp_set_logical_device(dev);
177 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200178 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000179}
180
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200181void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000182{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000183 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200184 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000185 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000186 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200187 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000188 }
189}
190
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200191void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200192{
Nico Huberdd4715b2013-06-10 22:08:35 +0200193 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200194 pnp_set_logical_device(dev);
195 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200196 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200197}
198
Eric Biederman5cd81732004-03-11 15:01:31 +0000199struct device_operations pnp_ops = {
200 .read_resources = pnp_read_resources,
201 .set_resources = pnp_set_resources,
202 .enable_resources = pnp_enable_resources,
203 .enable = pnp_enable,
204};
205
Uwe Hermanne4870472010-11-04 23:23:47 +0000206/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000207
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200208static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000209{
210 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200211 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000212
Felix Heldf2ec6482018-07-27 02:31:09 +0200213 /* If none of the mask bits is set, the resource would occupy the whole
214 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500215 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000216 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
217 dev_path(dev), index);
218 return;
219 }
220
Eric Biederman03acab62004-10-14 21:25:53 +0000221 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000222 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000223
Felix Heldf2ec6482018-07-27 02:31:09 +0200224 /* Calculate IO region size which is determined by the first one from
225 the LSB of the mask. */
226 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
227 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000228
Felix Heldf2ec6482018-07-27 02:31:09 +0200229 resource->gran = bit;
230 resource->align = bit;
231 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000232
Felix Heldf2ec6482018-07-27 02:31:09 +0200233 /* Calculate IO region address limit which is determined by the first
234 one from the MSB of the mask. */
235 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
236 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000237
Felix Heldf2ec6482018-07-27 02:31:09 +0200238 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000239
Felix Heldf2ec6482018-07-27 02:31:09 +0200240 /* The block of ones in the mask is expected to be continuous.
241 If there is any zero inbetween the block of ones, it is ignored
242 in the calculation of the resource size and limit. */
243 if (mask != (resource->limit ^ (resource->size - 1)))
244 printk(BIOS_WARNING,
245 "WARNING: mask of device %s index %d is wrong.\n",
246 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000247}
248
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200249static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000250{
251 struct resource *resource;
252
Uwe Hermanne4870472010-11-04 23:23:47 +0000253 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500254 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000255 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500256 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000257 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500258 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000259 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500260 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Michael Niewöhner6e016f02020-12-26 22:20:49 +0100261 if (info->flags & PNP_IO4)
262 pnp_get_ioresource(dev, PNP_IDX_IO4, info->io4);
Uwe Hermanne4870472010-11-04 23:23:47 +0000263
Eric Biederman5cd81732004-03-11 15:01:31 +0000264 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000265 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000266 resource->size = 1;
267 resource->flags |= IORESOURCE_IRQ;
268 }
269 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000270 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000271 resource->size = 1;
272 resource->flags |= IORESOURCE_IRQ;
273 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000274
Eric Biederman5cd81732004-03-11 15:01:31 +0000275 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000276 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000277 resource->size = 1;
278 resource->flags |= IORESOURCE_DRQ;
279 }
280 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000281 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000282 resource->size = 1;
283 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000284 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000285
286 /*
287 * These are not IRQs, but set the flag to have the
288 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000289 */
290 if (info->flags & PNP_EN) {
291 resource = new_resource(dev, PNP_IDX_EN);
292 resource->size = 1;
293 resource->flags |= IORESOURCE_IRQ;
294 }
295 if (info->flags & PNP_MSC0) {
296 resource = new_resource(dev, PNP_IDX_MSC0);
297 resource->size = 1;
298 resource->flags |= IORESOURCE_IRQ;
299 }
300 if (info->flags & PNP_MSC1) {
301 resource = new_resource(dev, PNP_IDX_MSC1);
302 resource->size = 1;
303 resource->flags |= IORESOURCE_IRQ;
304 }
Damien Zammit62c02762015-12-28 23:04:47 +1100305 if (info->flags & PNP_MSC2) {
306 resource = new_resource(dev, PNP_IDX_MSC2);
307 resource->size = 1;
308 resource->flags |= IORESOURCE_IRQ;
309 }
310 if (info->flags & PNP_MSC3) {
311 resource = new_resource(dev, PNP_IDX_MSC3);
312 resource->size = 1;
313 resource->flags |= IORESOURCE_IRQ;
314 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800315 if (info->flags & PNP_MSC4) {
316 resource = new_resource(dev, PNP_IDX_MSC4);
317 resource->size = 1;
318 resource->flags |= IORESOURCE_IRQ;
319 }
Damien Zammit62c02762015-12-28 23:04:47 +1100320 if (info->flags & PNP_MSC5) {
321 resource = new_resource(dev, PNP_IDX_MSC5);
322 resource->size = 1;
323 resource->flags |= IORESOURCE_IRQ;
324 }
325 if (info->flags & PNP_MSC6) {
326 resource = new_resource(dev, PNP_IDX_MSC6);
327 resource->size = 1;
328 resource->flags |= IORESOURCE_IRQ;
329 }
330 if (info->flags & PNP_MSC7) {
331 resource = new_resource(dev, PNP_IDX_MSC7);
332 resource->size = 1;
333 resource->flags |= IORESOURCE_IRQ;
334 }
335 if (info->flags & PNP_MSC8) {
336 resource = new_resource(dev, PNP_IDX_MSC8);
337 resource->size = 1;
338 resource->flags |= IORESOURCE_IRQ;
339 }
340 if (info->flags & PNP_MSC9) {
341 resource = new_resource(dev, PNP_IDX_MSC9);
342 resource->size = 1;
343 resource->flags |= IORESOURCE_IRQ;
344 }
345 if (info->flags & PNP_MSCA) {
346 resource = new_resource(dev, PNP_IDX_MSCA);
347 resource->size = 1;
348 resource->flags |= IORESOURCE_IRQ;
349 }
350 if (info->flags & PNP_MSCB) {
351 resource = new_resource(dev, PNP_IDX_MSCB);
352 resource->size = 1;
353 resource->flags |= IORESOURCE_IRQ;
354 }
355 if (info->flags & PNP_MSCC) {
356 resource = new_resource(dev, PNP_IDX_MSCC);
357 resource->size = 1;
358 resource->flags |= IORESOURCE_IRQ;
359 }
360 if (info->flags & PNP_MSCD) {
361 resource = new_resource(dev, PNP_IDX_MSCD);
362 resource->size = 1;
363 resource->flags |= IORESOURCE_IRQ;
364 }
365 if (info->flags & PNP_MSCE) {
366 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700367 resource->size = 1;
368 resource->flags |= IORESOURCE_IRQ;
369 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000370}
Eric Biederman5cd81732004-03-11 15:01:31 +0000371
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200372void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000373 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000374{
375 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200376 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000377 int i;
378
Uwe Hermannd453dd02010-10-18 00:00:57 +0000379 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000380 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000381
Uwe Hermannd453dd02010-10-18 00:00:57 +0000382 /* Setup the ops and resources on the newly allocated devices. */
383 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000384 /* Skip logical devices this Super I/O doesn't have. */
Felix Held7b7bc592019-12-15 13:53:48 +0100385 if (info[i].function == PNP_SKIP_FUNCTION)
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000386 continue;
387
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000388 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000389 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000390
Uwe Hermannd453dd02010-10-18 00:00:57 +0000391 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000392 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000393 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000394
Felix Held745e58a2018-07-06 19:38:24 +0200395 /* use LDN-specific ops override from corresponding pnp_info
396 entry if not NULL */
397 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000398 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200399 /* else use device ops */
400 else
401 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000402
Eric Biederman5cd81732004-03-11 15:01:31 +0000403 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000404 }
405}