blob: afe6948a3a0de25dd3ed757283406e1e5a830527 [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
Elyes HAOUASb77cf622018-05-02 21:01:18 +020050void pnp_set_logical_device(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000051{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000052 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
Eric Biederman5cd81732004-03-11 15:01:31 +000053}
54
Elyes HAOUASb77cf622018-05-02 21:01:18 +020055void pnp_set_enable(struct device *dev, int enable)
Eric Biederman5cd81732004-03-11 15:01:31 +000056{
Uwe Hermannd453dd02010-10-18 00:00:57 +000057 u8 tmp, bitpos;
Rudolf Marek623df672008-02-18 20:32:46 +000058
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020059 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000060
61 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000062 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Rudolf Marek623df672008-02-18 20:32:46 +000063
Uwe Hermannd453dd02010-10-18 00:00:57 +000064 if (enable)
Rudolf Marek623df672008-02-18 20:32:46 +000065 tmp |= (1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000066 else
Rudolf Marek623df672008-02-18 20:32:46 +000067 tmp &= ~(1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000068
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020069 pnp_write_config(dev, PNP_IDX_EN, tmp);
Eric Biederman5cd81732004-03-11 15:01:31 +000070}
71
Elyes HAOUASb77cf622018-05-02 21:01:18 +020072int pnp_read_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000073{
Uwe Hermannd453dd02010-10-18 00:00:57 +000074 u8 tmp, bitpos;
75
Elyes HAOUAS79a3de12020-08-26 19:52:40 +020076 tmp = pnp_read_config(dev, PNP_IDX_EN);
Uwe Hermannd453dd02010-10-18 00:00:57 +000077
78 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000079 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Uwe Hermannd453dd02010-10-18 00:00:57 +000080
Rudolf Marekb05d4bb2008-02-19 20:30:25 +000081 return !!(tmp & (1 << bitpos));
Eric Biederman5cd81732004-03-11 15:01:31 +000082}
83
Elyes HAOUASb77cf622018-05-02 21:01:18 +020084void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
Eric Biederman5cd81732004-03-11 15:01:31 +000085{
Uwe Hermannd453dd02010-10-18 00:00:57 +000086 /* Index == 0x60 or 0x62. */
Eric Biederman5cd81732004-03-11 15:01:31 +000087 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
88 pnp_write_config(dev, index + 1, iobase & 0xff);
89}
90
Elyes HAOUASb77cf622018-05-02 21:01:18 +020091void pnp_set_irq(struct device *dev, u8 index, u8 irq)
Eric Biederman5cd81732004-03-11 15:01:31 +000092{
Uwe Hermannd453dd02010-10-18 00:00:57 +000093 /* Index == 0x70 or 0x72. */
Eric Biederman5cd81732004-03-11 15:01:31 +000094 pnp_write_config(dev, index, irq);
95}
96
Elyes HAOUASb77cf622018-05-02 21:01:18 +020097void pnp_set_drq(struct device *dev, u8 index, u8 drq)
Eric Biederman5cd81732004-03-11 15:01:31 +000098{
Uwe Hermannd453dd02010-10-18 00:00:57 +000099 /* Index == 0x74. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000100 pnp_write_config(dev, index, drq & 0xff);
101}
102
103/* PNP device operations */
104
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200105void pnp_read_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000106{
107 return;
108}
109
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200110static void pnp_set_resource(struct device *dev, struct resource *resource)
Eric Biederman5cd81732004-03-11 15:01:31 +0000111{
112 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Elyes HAOUAS495bb662019-09-23 13:15:41 +0200113 /* The PNP_MSC Super IO registers have the IRQ flag set. If no
Felix Helda6627772018-07-27 16:41:32 +0200114 value is assigned in the devicetree, the corresponding
115 PNP_MSC register doesn't get written, which should be printed
116 as warning and not as error. */
117 if (resource->flags & IORESOURCE_IRQ &&
118 (resource->index != PNP_IDX_IRQ0) &&
119 (resource->index != PNP_IDX_IRQ1))
120 printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
Felix Held24d0ed72020-01-30 19:52:23 +0100121 "0x%010llx not assigned in devicetree\n", dev_path(dev),
Felix Helda6627772018-07-27 16:41:32 +0200122 resource->index, resource_type(resource),
123 resource->size);
124 else
125 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
Felix Held24d0ed72020-01-30 19:52:23 +0100126 "not assigned in devicetree\n", dev_path(dev), resource->index,
Felix Helda6627772018-07-27 16:41:32 +0200127 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000128 return;
129 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000130
Uwe Hermannd453dd02010-10-18 00:00:57 +0000131 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000132 if (resource->flags & IORESOURCE_IO) {
133 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000134 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000135 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000136 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000137 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000138 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000139 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000140 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000141 return;
142 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000143 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000144
Eric Biederman03acab62004-10-14 21:25:53 +0000145 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000146}
147
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200148void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000149{
Myles Watsonc25cc112010-05-21 14:33:48 +0000150 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000151
Nico Huberdd4715b2013-06-10 22:08:35 +0200152 pnp_enter_conf_mode(dev);
153
Uwe Hermannd453dd02010-10-18 00:00:57 +0000154 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000155 pnp_set_logical_device(dev);
156
157 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000158 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000159 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200160
161 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000162}
163
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200164void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000165{
Nico Huberdd4715b2013-06-10 22:08:35 +0200166 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000167 pnp_set_logical_device(dev);
168 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200169 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000170}
171
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200172void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000173{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000174 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200175 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000176 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000177 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200178 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000179 }
180}
181
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200182void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200183{
Nico Huberdd4715b2013-06-10 22:08:35 +0200184 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200185 pnp_set_logical_device(dev);
186 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200187 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200188}
189
Eric Biederman5cd81732004-03-11 15:01:31 +0000190struct device_operations pnp_ops = {
191 .read_resources = pnp_read_resources,
192 .set_resources = pnp_set_resources,
193 .enable_resources = pnp_enable_resources,
194 .enable = pnp_enable,
195};
196
Uwe Hermanne4870472010-11-04 23:23:47 +0000197/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000198
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200199static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000200{
201 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200202 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000203
Felix Heldf2ec6482018-07-27 02:31:09 +0200204 /* If none of the mask bits is set, the resource would occupy the whole
205 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500206 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000207 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
208 dev_path(dev), index);
209 return;
210 }
211
Eric Biederman03acab62004-10-14 21:25:53 +0000212 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000213 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000214
Felix Heldf2ec6482018-07-27 02:31:09 +0200215 /* Calculate IO region size which is determined by the first one from
216 the LSB of the mask. */
217 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
218 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000219
Felix Heldf2ec6482018-07-27 02:31:09 +0200220 resource->gran = bit;
221 resource->align = bit;
222 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000223
Felix Heldf2ec6482018-07-27 02:31:09 +0200224 /* Calculate IO region address limit which is determined by the first
225 one from the MSB of the mask. */
226 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
227 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000228
Felix Heldf2ec6482018-07-27 02:31:09 +0200229 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000230
Felix Heldf2ec6482018-07-27 02:31:09 +0200231 /* The block of ones in the mask is expected to be continuous.
232 If there is any zero inbetween the block of ones, it is ignored
233 in the calculation of the resource size and limit. */
234 if (mask != (resource->limit ^ (resource->size - 1)))
235 printk(BIOS_WARNING,
236 "WARNING: mask of device %s index %d is wrong.\n",
237 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000238}
239
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200240static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000241{
242 struct resource *resource;
243
Uwe Hermanne4870472010-11-04 23:23:47 +0000244 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500245 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000246 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500247 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000248 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500249 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000250 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500251 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Uwe Hermanne4870472010-11-04 23:23:47 +0000252
Eric Biederman5cd81732004-03-11 15:01:31 +0000253 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000254 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000255 resource->size = 1;
256 resource->flags |= IORESOURCE_IRQ;
257 }
258 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000259 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000260 resource->size = 1;
261 resource->flags |= IORESOURCE_IRQ;
262 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000263
Eric Biederman5cd81732004-03-11 15:01:31 +0000264 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000265 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000266 resource->size = 1;
267 resource->flags |= IORESOURCE_DRQ;
268 }
269 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000270 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000271 resource->size = 1;
272 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000273 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000274
275 /*
276 * These are not IRQs, but set the flag to have the
277 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000278 */
279 if (info->flags & PNP_EN) {
280 resource = new_resource(dev, PNP_IDX_EN);
281 resource->size = 1;
282 resource->flags |= IORESOURCE_IRQ;
283 }
284 if (info->flags & PNP_MSC0) {
285 resource = new_resource(dev, PNP_IDX_MSC0);
286 resource->size = 1;
287 resource->flags |= IORESOURCE_IRQ;
288 }
289 if (info->flags & PNP_MSC1) {
290 resource = new_resource(dev, PNP_IDX_MSC1);
291 resource->size = 1;
292 resource->flags |= IORESOURCE_IRQ;
293 }
Damien Zammit62c02762015-12-28 23:04:47 +1100294 if (info->flags & PNP_MSC2) {
295 resource = new_resource(dev, PNP_IDX_MSC2);
296 resource->size = 1;
297 resource->flags |= IORESOURCE_IRQ;
298 }
299 if (info->flags & PNP_MSC3) {
300 resource = new_resource(dev, PNP_IDX_MSC3);
301 resource->size = 1;
302 resource->flags |= IORESOURCE_IRQ;
303 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800304 if (info->flags & PNP_MSC4) {
305 resource = new_resource(dev, PNP_IDX_MSC4);
306 resource->size = 1;
307 resource->flags |= IORESOURCE_IRQ;
308 }
Damien Zammit62c02762015-12-28 23:04:47 +1100309 if (info->flags & PNP_MSC5) {
310 resource = new_resource(dev, PNP_IDX_MSC5);
311 resource->size = 1;
312 resource->flags |= IORESOURCE_IRQ;
313 }
314 if (info->flags & PNP_MSC6) {
315 resource = new_resource(dev, PNP_IDX_MSC6);
316 resource->size = 1;
317 resource->flags |= IORESOURCE_IRQ;
318 }
319 if (info->flags & PNP_MSC7) {
320 resource = new_resource(dev, PNP_IDX_MSC7);
321 resource->size = 1;
322 resource->flags |= IORESOURCE_IRQ;
323 }
324 if (info->flags & PNP_MSC8) {
325 resource = new_resource(dev, PNP_IDX_MSC8);
326 resource->size = 1;
327 resource->flags |= IORESOURCE_IRQ;
328 }
329 if (info->flags & PNP_MSC9) {
330 resource = new_resource(dev, PNP_IDX_MSC9);
331 resource->size = 1;
332 resource->flags |= IORESOURCE_IRQ;
333 }
334 if (info->flags & PNP_MSCA) {
335 resource = new_resource(dev, PNP_IDX_MSCA);
336 resource->size = 1;
337 resource->flags |= IORESOURCE_IRQ;
338 }
339 if (info->flags & PNP_MSCB) {
340 resource = new_resource(dev, PNP_IDX_MSCB);
341 resource->size = 1;
342 resource->flags |= IORESOURCE_IRQ;
343 }
344 if (info->flags & PNP_MSCC) {
345 resource = new_resource(dev, PNP_IDX_MSCC);
346 resource->size = 1;
347 resource->flags |= IORESOURCE_IRQ;
348 }
349 if (info->flags & PNP_MSCD) {
350 resource = new_resource(dev, PNP_IDX_MSCD);
351 resource->size = 1;
352 resource->flags |= IORESOURCE_IRQ;
353 }
354 if (info->flags & PNP_MSCE) {
355 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700356 resource->size = 1;
357 resource->flags |= IORESOURCE_IRQ;
358 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000359}
Eric Biederman5cd81732004-03-11 15:01:31 +0000360
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200361void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000362 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000363{
364 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200365 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000366 int i;
367
Uwe Hermannd453dd02010-10-18 00:00:57 +0000368 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000369 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000370
Uwe Hermannd453dd02010-10-18 00:00:57 +0000371 /* Setup the ops and resources on the newly allocated devices. */
372 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000373 /* Skip logical devices this Super I/O doesn't have. */
Felix Held7b7bc592019-12-15 13:53:48 +0100374 if (info[i].function == PNP_SKIP_FUNCTION)
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000375 continue;
376
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000377 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000378 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000379
Uwe Hermannd453dd02010-10-18 00:00:57 +0000380 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000381 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000382 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000383
Felix Held745e58a2018-07-06 19:38:24 +0200384 /* use LDN-specific ops override from corresponding pnp_info
385 entry if not NULL */
386 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000387 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200388 /* else use device ops */
389 else
390 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000391
Eric Biederman5cd81732004-03-11 15:01:31 +0000392 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000393 }
394}