xref: /qemu/hw/net/can/can_pcm3680_pci.c (revision 2155d2dd7f733674586119b6b4ee0f52d2032779)
1  /*
2   * PCM-3680i PCI CAN device (SJA1000 based) emulation
3   *
4   * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
5   *
6   * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
7   * Jin Yang and Pavel Pisa
8   *
9   * Permission is hereby granted, free of charge, to any person obtaining a copy
10   * of this software and associated documentation files (the "Software"), to deal
11   * in the Software without restriction, including without limitation the rights
12   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13   * copies of the Software, and to permit persons to whom the Software is
14   * furnished to do so, subject to the following conditions:
15   *
16   * The above copyright notice and this permission notice shall be included in
17   * all copies or substantial portions of the Software.
18   *
19   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25   * THE SOFTWARE.
26   */
27  
28  #include "qemu/osdep.h"
29  #include "qemu/event_notifier.h"
30  #include "qemu/module.h"
31  #include "qemu/thread.h"
32  #include "qemu/sockets.h"
33  #include "qapi/error.h"
34  #include "chardev/char.h"
35  #include "hw/irq.h"
36  #include "hw/pci/pci_device.h"
37  #include "hw/qdev-properties.h"
38  #include "migration/vmstate.h"
39  #include "net/can_emu.h"
40  
41  #include "can_sja1000.h"
42  #include "qom/object.h"
43  
44  #define TYPE_CAN_PCI_DEV "pcm3680_pci"
45  
46  typedef struct Pcm3680iPCIState Pcm3680iPCIState;
47  DECLARE_INSTANCE_CHECKER(Pcm3680iPCIState, PCM3680i_PCI_DEV,
48                           TYPE_CAN_PCI_DEV)
49  
50  /* the PCI device and vendor IDs */
51  #ifndef PCM3680i_PCI_VENDOR_ID1
52  #define PCM3680i_PCI_VENDOR_ID1     0x13fe
53  #endif
54  
55  #ifndef PCM3680i_PCI_DEVICE_ID1
56  #define PCM3680i_PCI_DEVICE_ID1     0xc002
57  #endif
58  
59  #define PCM3680i_PCI_SJA_COUNT     2
60  #define PCM3680i_PCI_SJA_RANGE     0x100
61  
62  #define PCM3680i_PCI_BYTES_PER_SJA 0x20
63  
64  struct Pcm3680iPCIState {
65      /*< private >*/
66      PCIDevice       dev;
67      /*< public >*/
68      MemoryRegion    sja_io[PCM3680i_PCI_SJA_COUNT];
69  
70      CanSJA1000State sja_state[PCM3680i_PCI_SJA_COUNT];
71      qemu_irq        irq;
72  
73      char            *model; /* The model that support, only SJA1000 now. */
74      CanBusState     *canbus[PCM3680i_PCI_SJA_COUNT];
75  };
76  
77  static void pcm3680i_pci_reset(DeviceState *dev)
78  {
79      Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
80      int i;
81  
82      for (i = 0; i < PCM3680i_PCI_SJA_COUNT; i++) {
83          can_sja_hardware_reset(&d->sja_state[i]);
84      }
85  }
86  
87  static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
88                                            unsigned size)
89  {
90      Pcm3680iPCIState *d = opaque;
91      CanSJA1000State *s = &d->sja_state[0];
92  
93      if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
94          return 0;
95      }
96  
97      return can_sja_mem_read(s, addr, size);
98  }
99  
100  static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
101                                         uint64_t data, unsigned size)
102  {
103      Pcm3680iPCIState *d = opaque;
104      CanSJA1000State *s = &d->sja_state[0];
105  
106      if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
107          return;
108      }
109  
110      can_sja_mem_write(s, addr, data, size);
111  }
112  
113  static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
114                                            unsigned size)
115  {
116      Pcm3680iPCIState *d = opaque;
117      CanSJA1000State *s = &d->sja_state[1];
118  
119      if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
120          return 0;
121      }
122  
123      return can_sja_mem_read(s, addr, size);
124  }
125  
126  static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
127                               unsigned size)
128  {
129      Pcm3680iPCIState *d = opaque;
130      CanSJA1000State *s = &d->sja_state[1];
131  
132      if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
133          return;
134      }
135  
136      can_sja_mem_write(s, addr, data, size);
137  }
138  
139  static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
140      .read = pcm3680i_pci_sja1_io_read,
141      .write = pcm3680i_pci_sja1_io_write,
142      .endianness = DEVICE_LITTLE_ENDIAN,
143      .impl = {
144          .max_access_size = 1,
145      },
146  };
147  
148  static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
149      .read = pcm3680i_pci_sja2_io_read,
150      .write = pcm3680i_pci_sja2_io_write,
151      .endianness = DEVICE_LITTLE_ENDIAN,
152      .impl = {
153          .max_access_size = 1,
154      },
155  };
156  
157  static void pcm3680i_pci_realize(PCIDevice *pci_dev, Error **errp)
158  {
159      Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
160      uint8_t *pci_conf;
161      int i;
162  
163      pci_conf = pci_dev->config;
164      pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
165  
166      d->irq = pci_allocate_irq(&d->dev);
167  
168      for (i = 0; i < PCM3680i_PCI_SJA_COUNT; i++) {
169          can_sja_init(&d->sja_state[i], d->irq);
170      }
171  
172      for (i = 0; i < PCM3680i_PCI_SJA_COUNT; i++) {
173          if (can_sja_connect_to_bus(&d->sja_state[i], d->canbus[i]) < 0) {
174              error_setg(errp, "can_sja_connect_to_bus failed");
175              return;
176          }
177      }
178  
179      memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
180                            d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE);
181  
182      memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
183                            d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE);
184  
185      for (i = 0; i < PCM3680i_PCI_SJA_COUNT; i++) {
186          pci_register_bar(&d->dev, /*BAR*/ i, PCI_BASE_ADDRESS_SPACE_IO,
187                           &d->sja_io[i]);
188      }
189  }
190  
191  static void pcm3680i_pci_exit(PCIDevice *pci_dev)
192  {
193      Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
194      int i;
195  
196      for (i = 0; i < PCM3680i_PCI_SJA_COUNT; i++) {
197          can_sja_disconnect(&d->sja_state[i]);
198      }
199  
200      qemu_free_irq(d->irq);
201  }
202  
203  static const VMStateDescription vmstate_pcm3680i_pci = {
204      .name = "pcm3680i_pci",
205      .version_id = 1,
206      .minimum_version_id = 1,
207      .fields = (const VMStateField[]) {
208          VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
209          VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
210                         vmstate_can_sja, CanSJA1000State),
211          VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
212                         vmstate_can_sja, CanSJA1000State),
213          VMSTATE_END_OF_LIST()
214      }
215  };
216  
217  static void pcm3680i_pci_instance_init(Object *obj)
218  {
219      Pcm3680iPCIState *d = PCM3680i_PCI_DEV(obj);
220  
221      object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
222                               (Object **)&d->canbus[0],
223                               qdev_prop_allow_set_link_before_realize,
224                               0);
225      object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
226                               (Object **)&d->canbus[1],
227                               qdev_prop_allow_set_link_before_realize,
228                               0);
229  }
230  
231  static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
232  {
233      DeviceClass *dc = DEVICE_CLASS(klass);
234      PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
235  
236      k->realize = pcm3680i_pci_realize;
237      k->exit = pcm3680i_pci_exit;
238      k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
239      k->device_id = PCM3680i_PCI_DEVICE_ID1;
240      k->revision = 0x00;
241      k->class_id = 0x000c09;
242      k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
243      k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
244      dc->desc = "Pcm3680i PCICANx";
245      dc->vmsd = &vmstate_pcm3680i_pci;
246      set_bit(DEVICE_CATEGORY_MISC, dc->categories);
247      device_class_set_legacy_reset(dc, pcm3680i_pci_reset);
248  }
249  
250  static const TypeInfo pcm3680i_pci_info = {
251      .name          = TYPE_CAN_PCI_DEV,
252      .parent        = TYPE_PCI_DEVICE,
253      .instance_size = sizeof(Pcm3680iPCIState),
254      .class_init    = pcm3680i_pci_class_init,
255      .instance_init = pcm3680i_pci_instance_init,
256      .interfaces = (InterfaceInfo[]) {
257          { INTERFACE_CONVENTIONAL_PCI_DEVICE },
258          { },
259      },
260  };
261  
262  static void pcm3680i_pci_register_types(void)
263  {
264      type_register_static(&pcm3680i_pci_info);
265  }
266  
267  type_init(pcm3680i_pci_register_types)
268