blob: 259d44975240f3967ecdf7d109006a6f5b9de6b7 [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);
Michael Niewöhner6e016f02020-12-26 22:20:49 +0100252 if (info->flags & PNP_IO4)
253 pnp_get_ioresource(dev, PNP_IDX_IO4, info->io4);
Uwe Hermanne4870472010-11-04 23:23:47 +0000254
Eric Biederman5cd81732004-03-11 15:01:31 +0000255 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000256 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000257 resource->size = 1;
258 resource->flags |= IORESOURCE_IRQ;
259 }
260 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000261 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000262 resource->size = 1;
263 resource->flags |= IORESOURCE_IRQ;
264 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000265
Eric Biederman5cd81732004-03-11 15:01:31 +0000266 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000267 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000268 resource->size = 1;
269 resource->flags |= IORESOURCE_DRQ;
270 }
271 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000272 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000273 resource->size = 1;
274 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000275 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000276
277 /*
278 * These are not IRQs, but set the flag to have the
279 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000280 */
281 if (info->flags & PNP_EN) {
282 resource = new_resource(dev, PNP_IDX_EN);
283 resource->size = 1;
284 resource->flags |= IORESOURCE_IRQ;
285 }
286 if (info->flags & PNP_MSC0) {
287 resource = new_resource(dev, PNP_IDX_MSC0);
288 resource->size = 1;
289 resource->flags |= IORESOURCE_IRQ;
290 }
291 if (info->flags & PNP_MSC1) {
292 resource = new_resource(dev, PNP_IDX_MSC1);
293 resource->size = 1;
294 resource->flags |= IORESOURCE_IRQ;
295 }
Damien Zammit62c02762015-12-28 23:04:47 +1100296 if (info->flags & PNP_MSC2) {
297 resource = new_resource(dev, PNP_IDX_MSC2);
298 resource->size = 1;
299 resource->flags |= IORESOURCE_IRQ;
300 }
301 if (info->flags & PNP_MSC3) {
302 resource = new_resource(dev, PNP_IDX_MSC3);
303 resource->size = 1;
304 resource->flags |= IORESOURCE_IRQ;
305 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800306 if (info->flags & PNP_MSC4) {
307 resource = new_resource(dev, PNP_IDX_MSC4);
308 resource->size = 1;
309 resource->flags |= IORESOURCE_IRQ;
310 }
Damien Zammit62c02762015-12-28 23:04:47 +1100311 if (info->flags & PNP_MSC5) {
312 resource = new_resource(dev, PNP_IDX_MSC5);
313 resource->size = 1;
314 resource->flags |= IORESOURCE_IRQ;
315 }
316 if (info->flags & PNP_MSC6) {
317 resource = new_resource(dev, PNP_IDX_MSC6);
318 resource->size = 1;
319 resource->flags |= IORESOURCE_IRQ;
320 }
321 if (info->flags & PNP_MSC7) {
322 resource = new_resource(dev, PNP_IDX_MSC7);
323 resource->size = 1;
324 resource->flags |= IORESOURCE_IRQ;
325 }
326 if (info->flags & PNP_MSC8) {
327 resource = new_resource(dev, PNP_IDX_MSC8);
328 resource->size = 1;
329 resource->flags |= IORESOURCE_IRQ;
330 }
331 if (info->flags & PNP_MSC9) {
332 resource = new_resource(dev, PNP_IDX_MSC9);
333 resource->size = 1;
334 resource->flags |= IORESOURCE_IRQ;
335 }
336 if (info->flags & PNP_MSCA) {
337 resource = new_resource(dev, PNP_IDX_MSCA);
338 resource->size = 1;
339 resource->flags |= IORESOURCE_IRQ;
340 }
341 if (info->flags & PNP_MSCB) {
342 resource = new_resource(dev, PNP_IDX_MSCB);
343 resource->size = 1;
344 resource->flags |= IORESOURCE_IRQ;
345 }
346 if (info->flags & PNP_MSCC) {
347 resource = new_resource(dev, PNP_IDX_MSCC);
348 resource->size = 1;
349 resource->flags |= IORESOURCE_IRQ;
350 }
351 if (info->flags & PNP_MSCD) {
352 resource = new_resource(dev, PNP_IDX_MSCD);
353 resource->size = 1;
354 resource->flags |= IORESOURCE_IRQ;
355 }
356 if (info->flags & PNP_MSCE) {
357 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700358 resource->size = 1;
359 resource->flags |= IORESOURCE_IRQ;
360 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000361}
Eric Biederman5cd81732004-03-11 15:01:31 +0000362
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200363void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000364 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000365{
366 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200367 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000368 int i;
369
Uwe Hermannd453dd02010-10-18 00:00:57 +0000370 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000371 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000372
Uwe Hermannd453dd02010-10-18 00:00:57 +0000373 /* Setup the ops and resources on the newly allocated devices. */
374 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000375 /* Skip logical devices this Super I/O doesn't have. */
Felix Held7b7bc592019-12-15 13:53:48 +0100376 if (info[i].function == PNP_SKIP_FUNCTION)
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000377 continue;
378
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000379 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000380 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000381
Uwe Hermannd453dd02010-10-18 00:00:57 +0000382 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000383 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000384 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000385
Felix Held745e58a2018-07-06 19:38:24 +0200386 /* use LDN-specific ops override from corresponding pnp_info
387 entry if not NULL */
388 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000389 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200390 /* else use device ops */
391 else
392 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000393
Eric Biederman5cd81732004-03-11 15:01:31 +0000394 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000395 }
396}