blob: 9fa032e4a950335408ae34d1d4a45df0c32e95a6 [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>
Elyes HAOUAS79a3de12020-08-26 19:52:40 +02008#include <device/pnp_def.h>
Eric Biederman5cd81732004-03-11 15:01:31 +00009
Nico Huberdd4715b2013-06-10 22:08:35 +020010/* PNP config mode wrappers */
11
Elyes HAOUASb77cf622018-05-02 21:01:18 +020012void pnp_enter_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020013{
14 if (dev->ops->ops_pnp_mode)
15 dev->ops->ops_pnp_mode->enter_conf_mode(dev);
16}
17
Elyes HAOUASb77cf622018-05-02 21:01:18 +020018void pnp_exit_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020019{
20 if (dev->ops->ops_pnp_mode)
21 dev->ops->ops_pnp_mode->exit_conf_mode(dev);
22}
23
Patrick Rudolph7db16dd2019-12-10 13:15:42 +010024#if CONFIG(HAVE_ACPI_TABLES)
25void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data)
26{
27 if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_enter_conf_mode)
28 dev->ops->ops_pnp_mode->ssdt_enter_conf_mode(dev, idx, data);
29}
30void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data)
31{
32 if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_exit_conf_mode)
33 dev->ops->ops_pnp_mode->ssdt_exit_conf_mode(dev, idx, data);
34}
35#endif
36
Eric Biederman5cd81732004-03-11 15:01:31 +000037/* PNP fundamental operations */
38
Elyes HAOUASb77cf622018-05-02 21:01:18 +020039void pnp_write_config(struct device *dev, u8 reg, u8 value)
Eric Biederman5cd81732004-03-11 15:01:31 +000040{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000041 outb(reg, dev->path.pnp.port);
42 outb(value, dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000043}
44
Elyes HAOUASb77cf622018-05-02 21:01:18 +020045u8 pnp_read_config(struct device *dev, u8 reg)
Eric Biederman5cd81732004-03-11 15:01:31 +000046{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000047 outb(reg, dev->path.pnp.port);
48 return inb(dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000049}
50
Elyes HAOUASb77cf622018-05-02 21:01:18 +020051void pnp_set_logical_device(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000052{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000053 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
Eric Biederman5cd81732004-03-11 15:01:31 +000054}
55
Elyes HAOUASb77cf622018-05-02 21:01:18 +020056void pnp_set_enable(struct device *dev, int enable)
Eric Biederman5cd81732004-03-11 15:01:31 +000057{
Uwe Hermannd453dd02010-10-18 00:00:57 +000058 u8 tmp, bitpos;
Rudolf Marek623df672008-02-18 20:32:46 +000059
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020060 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000061
62 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000063 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Rudolf Marek623df672008-02-18 20:32:46 +000064
Uwe Hermannd453dd02010-10-18 00:00:57 +000065 if (enable)
Rudolf Marek623df672008-02-18 20:32:46 +000066 tmp |= (1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000067 else
Rudolf Marek623df672008-02-18 20:32:46 +000068 tmp &= ~(1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000069
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020070 pnp_write_config(dev, PNP_IDX_EN, tmp);
Eric Biederman5cd81732004-03-11 15:01:31 +000071}
72
Elyes HAOUASb77cf622018-05-02 21:01:18 +020073int pnp_read_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000074{
Uwe Hermannd453dd02010-10-18 00:00:57 +000075 u8 tmp, bitpos;
76
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020077 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000078
79 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000080 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Uwe Hermannd453dd02010-10-18 00:00:57 +000081
Rudolf Marekb05d4bb2008-02-19 20:30:25 +000082 return !!(tmp & (1 << bitpos));
Eric Biederman5cd81732004-03-11 15:01:31 +000083}
84
Elyes HAOUASb77cf622018-05-02 21:01:18 +020085void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
Eric Biederman5cd81732004-03-11 15:01:31 +000086{
Uwe Hermannd453dd02010-10-18 00:00:57 +000087 /* Index == 0x60 or 0x62. */
Eric Biederman5cd81732004-03-11 15:01:31 +000088 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
89 pnp_write_config(dev, index + 1, iobase & 0xff);
90}
91
Elyes HAOUASb77cf622018-05-02 21:01:18 +020092void pnp_set_irq(struct device *dev, u8 index, u8 irq)
Eric Biederman5cd81732004-03-11 15:01:31 +000093{
Uwe Hermannd453dd02010-10-18 00:00:57 +000094 /* Index == 0x70 or 0x72. */
Eric Biederman5cd81732004-03-11 15:01:31 +000095 pnp_write_config(dev, index, irq);
96}
97
Elyes HAOUASb77cf622018-05-02 21:01:18 +020098void pnp_set_drq(struct device *dev, u8 index, u8 drq)
Eric Biederman5cd81732004-03-11 15:01:31 +000099{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000100 /* Index == 0x74. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000101 pnp_write_config(dev, index, drq & 0xff);
102}
103
104/* PNP device operations */
105
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200106void pnp_read_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000107{
108 return;
109}
110
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200111static void pnp_set_resource(struct device *dev, struct resource *resource)
Eric Biederman5cd81732004-03-11 15:01:31 +0000112{
113 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Elyes HAOUAS495bb662019-09-23 13:15:41 +0200114 /* The PNP_MSC Super IO registers have the IRQ flag set. If no
Felix Helda6627772018-07-27 16:41:32 +0200115 value is assigned in the devicetree, the corresponding
116 PNP_MSC register doesn't get written, which should be printed
117 as warning and not as error. */
118 if (resource->flags & IORESOURCE_IRQ &&
119 (resource->index != PNP_IDX_IRQ0) &&
120 (resource->index != PNP_IDX_IRQ1))
121 printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
Felix Held24d0ed72020-01-30 19:52:23 +0100122 "0x%010llx not assigned in devicetree\n", dev_path(dev),
Felix Helda6627772018-07-27 16:41:32 +0200123 resource->index, resource_type(resource),
124 resource->size);
125 else
126 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
Felix Held24d0ed72020-01-30 19:52:23 +0100127 "not assigned in devicetree\n", dev_path(dev), resource->index,
Felix Helda6627772018-07-27 16:41:32 +0200128 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000129 return;
130 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000131
Uwe Hermannd453dd02010-10-18 00:00:57 +0000132 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000133 if (resource->flags & IORESOURCE_IO) {
134 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000135 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000136 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000137 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000138 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000139 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000140 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000141 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000142 return;
143 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000144 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000145
Eric Biederman03acab62004-10-14 21:25:53 +0000146 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000147}
148
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200149void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000150{
Myles Watsonc25cc112010-05-21 14:33:48 +0000151 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000152
Nico Huberdd4715b2013-06-10 22:08:35 +0200153 pnp_enter_conf_mode(dev);
154
Uwe Hermannd453dd02010-10-18 00:00:57 +0000155 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000156 pnp_set_logical_device(dev);
157
158 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000159 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000160 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200161
162 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000163}
164
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200165void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000166{
Nico Huberdd4715b2013-06-10 22:08:35 +0200167 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000168 pnp_set_logical_device(dev);
169 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200170 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000171}
172
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200173void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000174{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000175 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200176 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000177 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000178 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200179 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000180 }
181}
182
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200183void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200184{
Nico Huberdd4715b2013-06-10 22:08:35 +0200185 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200186 pnp_set_logical_device(dev);
187 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200188 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200189}
190
Eric Biederman5cd81732004-03-11 15:01:31 +0000191struct device_operations pnp_ops = {
192 .read_resources = pnp_read_resources,
193 .set_resources = pnp_set_resources,
194 .enable_resources = pnp_enable_resources,
195 .enable = pnp_enable,
196};
197
Uwe Hermanne4870472010-11-04 23:23:47 +0000198/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000199
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200200static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000201{
202 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200203 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000204
Felix Heldf2ec6482018-07-27 02:31:09 +0200205 /* If none of the mask bits is set, the resource would occupy the whole
206 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500207 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000208 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
209 dev_path(dev), index);
210 return;
211 }
212
Eric Biederman03acab62004-10-14 21:25:53 +0000213 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000214 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000215
Felix Heldf2ec6482018-07-27 02:31:09 +0200216 /* Calculate IO region size which is determined by the first one from
217 the LSB of the mask. */
218 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
219 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000220
Felix Heldf2ec6482018-07-27 02:31:09 +0200221 resource->gran = bit;
222 resource->align = bit;
223 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000224
Felix Heldf2ec6482018-07-27 02:31:09 +0200225 /* Calculate IO region address limit which is determined by the first
226 one from the MSB of the mask. */
227 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
228 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000229
Felix Heldf2ec6482018-07-27 02:31:09 +0200230 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000231
Felix Heldf2ec6482018-07-27 02:31:09 +0200232 /* The block of ones in the mask is expected to be continuous.
233 If there is any zero inbetween the block of ones, it is ignored
234 in the calculation of the resource size and limit. */
235 if (mask != (resource->limit ^ (resource->size - 1)))
236 printk(BIOS_WARNING,
237 "WARNING: mask of device %s index %d is wrong.\n",
238 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000239}
240
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200241static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000242{
243 struct resource *resource;
244
Uwe Hermanne4870472010-11-04 23:23:47 +0000245 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500246 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000247 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500248 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000249 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500250 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000251 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500252 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Uwe Hermanne4870472010-11-04 23:23:47 +0000253
Eric Biederman5cd81732004-03-11 15:01:31 +0000254 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000255 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000256 resource->size = 1;
257 resource->flags |= IORESOURCE_IRQ;
258 }
259 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000260 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000261 resource->size = 1;
262 resource->flags |= IORESOURCE_IRQ;
263 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000264
Eric Biederman5cd81732004-03-11 15:01:31 +0000265 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000266 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000267 resource->size = 1;
268 resource->flags |= IORESOURCE_DRQ;
269 }
270 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000271 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000272 resource->size = 1;
273 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000274 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000275
276 /*
277 * These are not IRQs, but set the flag to have the
278 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000279 */
280 if (info->flags & PNP_EN) {
281 resource = new_resource(dev, PNP_IDX_EN);
282 resource->size = 1;
283 resource->flags |= IORESOURCE_IRQ;
284 }
285 if (info->flags & PNP_MSC0) {
286 resource = new_resource(dev, PNP_IDX_MSC0);
287 resource->size = 1;
288 resource->flags |= IORESOURCE_IRQ;
289 }
290 if (info->flags & PNP_MSC1) {
291 resource = new_resource(dev, PNP_IDX_MSC1);
292 resource->size = 1;
293 resource->flags |= IORESOURCE_IRQ;
294 }
Damien Zammit62c02762015-12-28 23:04:47 +1100295 if (info->flags & PNP_MSC2) {
296 resource = new_resource(dev, PNP_IDX_MSC2);
297 resource->size = 1;
298 resource->flags |= IORESOURCE_IRQ;
299 }
300 if (info->flags & PNP_MSC3) {
301 resource = new_resource(dev, PNP_IDX_MSC3);
302 resource->size = 1;
303 resource->flags |= IORESOURCE_IRQ;
304 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800305 if (info->flags & PNP_MSC4) {
306 resource = new_resource(dev, PNP_IDX_MSC4);
307 resource->size = 1;
308 resource->flags |= IORESOURCE_IRQ;
309 }
Damien Zammit62c02762015-12-28 23:04:47 +1100310 if (info->flags & PNP_MSC5) {
311 resource = new_resource(dev, PNP_IDX_MSC5);
312 resource->size = 1;
313 resource->flags |= IORESOURCE_IRQ;
314 }
315 if (info->flags & PNP_MSC6) {
316 resource = new_resource(dev, PNP_IDX_MSC6);
317 resource->size = 1;
318 resource->flags |= IORESOURCE_IRQ;
319 }
320 if (info->flags & PNP_MSC7) {
321 resource = new_resource(dev, PNP_IDX_MSC7);
322 resource->size = 1;
323 resource->flags |= IORESOURCE_IRQ;
324 }
325 if (info->flags & PNP_MSC8) {
326 resource = new_resource(dev, PNP_IDX_MSC8);
327 resource->size = 1;
328 resource->flags |= IORESOURCE_IRQ;
329 }
330 if (info->flags & PNP_MSC9) {
331 resource = new_resource(dev, PNP_IDX_MSC9);
332 resource->size = 1;
333 resource->flags |= IORESOURCE_IRQ;
334 }
335 if (info->flags & PNP_MSCA) {
336 resource = new_resource(dev, PNP_IDX_MSCA);
337 resource->size = 1;
338 resource->flags |= IORESOURCE_IRQ;
339 }
340 if (info->flags & PNP_MSCB) {
341 resource = new_resource(dev, PNP_IDX_MSCB);
342 resource->size = 1;
343 resource->flags |= IORESOURCE_IRQ;
344 }
345 if (info->flags & PNP_MSCC) {
346 resource = new_resource(dev, PNP_IDX_MSCC);
347 resource->size = 1;
348 resource->flags |= IORESOURCE_IRQ;
349 }
350 if (info->flags & PNP_MSCD) {
351 resource = new_resource(dev, PNP_IDX_MSCD);
352 resource->size = 1;
353 resource->flags |= IORESOURCE_IRQ;
354 }
355 if (info->flags & PNP_MSCE) {
356 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700357 resource->size = 1;
358 resource->flags |= IORESOURCE_IRQ;
359 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000360}
Eric Biederman5cd81732004-03-11 15:01:31 +0000361
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200362void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000363 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000364{
365 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200366 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000367 int i;
368
Uwe Hermannd453dd02010-10-18 00:00:57 +0000369 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000370 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000371
Uwe Hermannd453dd02010-10-18 00:00:57 +0000372 /* Setup the ops and resources on the newly allocated devices. */
373 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000374 /* Skip logical devices this Super I/O doesn't have. */
Felix Held7b7bc592019-12-15 13:53:48 +0100375 if (info[i].function == PNP_SKIP_FUNCTION)
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000376 continue;
377
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000378 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000379 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000380
Uwe Hermannd453dd02010-10-18 00:00:57 +0000381 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000382 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000383 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000384
Felix Held745e58a2018-07-06 19:38:24 +0200385 /* use LDN-specific ops override from corresponding pnp_info
386 entry if not NULL */
387 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000388 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200389 /* else use device ops */
390 else
391 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000392
Eric Biederman5cd81732004-03-11 15:01:31 +0000393 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000394 }
395}