1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Andrew Schultz
41 *          Ali Saidi
42 *          Miguel Serrano
43 */
44
45#include "dev/storage/ide_ctrl.hh"
46
47#include <string>
48
49#include "cpu/intr_control.hh"
50#include "debug/IdeCtrl.hh"
51#include "dev/storage/ide_disk.hh"
52#include "mem/packet.hh"
53#include "mem/packet_access.hh"
54#include "params/IdeController.hh"
55#include "sim/byteswap.hh"
56
57// clang complains about std::set being overloaded with Packet::set if
58// we open up the entire namespace std
59using std::string;
60
61// Bus master IDE registers
62enum BMIRegOffset {
63    BMICommand = 0x0,
64    BMIStatus = 0x2,
65    BMIDescTablePtr = 0x4
66};
67
68// PCI config space registers
69enum ConfRegOffset {
70    PrimaryTiming = 0x40,
71    SecondaryTiming = 0x42,
72    DeviceTiming = 0x44,
73    UDMAControl = 0x48,
74    UDMATiming = 0x4A,
75    IDEConfig = 0x54
76};
77
78static const uint16_t timeRegWithDecodeEn = 0x8000;
79
80IdeController::Channel::Channel(
81        string newName, Addr _cmdSize, Addr _ctrlSize) :
82    _name(newName),
83    cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
84    master(NULL), slave(NULL), selected(NULL)
85{
86    bmiRegs.reset();
87    bmiRegs.status.dmaCap0 = 1;
88    bmiRegs.status.dmaCap1 = 1;
89}
90
91IdeController::Channel::~Channel()
92{
93}
94
95IdeController::IdeController(Params *p)
96    : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
97    secondary(name() + ".secondary", BARSize[2], BARSize[3]),
98    bmiAddr(0), bmiSize(BARSize[4]),
99    primaryTiming(htole(timeRegWithDecodeEn)),
100    secondaryTiming(htole(timeRegWithDecodeEn)),
101    deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
102    ioEnabled(false), bmEnabled(false),
103    ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
104{
105
106    // Assign the disks to channels
107    for (int i = 0; i < params()->disks.size(); i++) {
108        if (!params()->disks[i])
109            continue;
110        switch (i) {
111          case 0:
112            primary.master = params()->disks[0];
113            break;
114          case 1:
115            primary.slave = params()->disks[1];
116            break;
117          case 2:
118            secondary.master = params()->disks[2];
119            break;
120          case 3:
121            secondary.slave = params()->disks[3];
122            break;
123          default:
124            panic("IDE controllers support a maximum "
125                  "of 4 devices attached!\n");
126        }
127        params()->disks[i]->setController(this);
128    }
129
130    primary.select(false);
131    secondary.select(false);
132
133    if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
134        primary.cmdAddr = BARAddrs[0];  primary.cmdSize = BARSize[0];
135        primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
136    }
137    if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
138        secondary.cmdAddr = BARAddrs[2];  secondary.cmdSize = BARSize[2];
139        secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
140    }
141
142    ioEnabled = (config.command & htole(PCI_CMD_IOSE));
143    bmEnabled = (config.command & htole(PCI_CMD_BME));
144}
145
146bool
147IdeController::isDiskSelected(IdeDisk *diskPtr)
148{
149    return (primary.selected == diskPtr || secondary.selected == diskPtr);
150}
151
152void
153IdeController::intrPost()
154{
155    primary.bmiRegs.status.intStatus = 1;
156    PciDevice::intrPost();
157}
158
159void
160IdeController::setDmaComplete(IdeDisk *disk)
161{
162    Channel *channel;
163    if (disk == primary.master || disk == primary.slave) {
164        channel = &primary;
165    } else if (disk == secondary.master || disk == secondary.slave) {
166        channel = &secondary;
167    } else {
168        panic("Unable to find disk based on pointer %#x\n", disk);
169    }
170
171    channel->bmiRegs.command.startStop = 0;
172    channel->bmiRegs.status.active = 0;
173    channel->bmiRegs.status.intStatus = 1;
174}
175
176Tick
177IdeController::readConfig(PacketPtr pkt)
178{
179    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
180    if (offset < PCI_DEVICE_SPECIFIC) {
181        return PciDevice::readConfig(pkt);
182    }
183
184    switch (pkt->getSize()) {
185      case sizeof(uint8_t):
186        switch (offset) {
187          case DeviceTiming:
188            pkt->setLE<uint8_t>(deviceTiming);
189            break;
190          case UDMAControl:
191            pkt->setLE<uint8_t>(udmaControl);
192            break;
193          case PrimaryTiming + 1:
194            pkt->setLE<uint8_t>(bits(htole(primaryTiming), 15, 8));
195            break;
196          case SecondaryTiming + 1:
197            pkt->setLE<uint8_t>(bits(htole(secondaryTiming), 15, 8));
198            break;
199          case IDEConfig:
200            pkt->setLE<uint8_t>(bits(htole(ideConfig), 7, 0));
201            break;
202          case IDEConfig + 1:
203            pkt->setLE<uint8_t>(bits(htole(ideConfig), 15, 8));
204            break;
205          default:
206            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
207                    offset);
208        }
209        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
210                (uint32_t)pkt->getLE<uint8_t>());
211        break;
212      case sizeof(uint16_t):
213        switch (offset) {
214          case UDMAControl:
215            pkt->setLE<uint16_t>(udmaControl);
216            break;
217          case PrimaryTiming:
218            pkt->setLE<uint16_t>(primaryTiming);
219            break;
220          case SecondaryTiming:
221            pkt->setLE<uint16_t>(secondaryTiming);
222            break;
223          case UDMATiming:
224            pkt->setLE<uint16_t>(udmaTiming);
225            break;
226          case IDEConfig:
227            pkt->setLE<uint16_t>(ideConfig);
228            break;
229          default:
230            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
231                    offset);
232        }
233        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
234                (uint32_t)pkt->getLE<uint16_t>());
235        break;
236      case sizeof(uint32_t):
237        switch (offset) {
238          case PrimaryTiming:
239            pkt->setLE<uint32_t>(primaryTiming);
240            break;
241          case IDEConfig:
242            pkt->setLE<uint32_t>(ideConfig);
243            break;
244          default:
245            panic("No 32bit reads implemented for this device.");
246        }
247        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
248                (uint32_t)pkt->getLE<uint32_t>());
249        break;
250      default:
251        panic("invalid access size(?) for PCI configspace!\n");
252    }
253    pkt->makeAtomicResponse();
254    return configDelay;
255}
256
257
258Tick
259IdeController::writeConfig(PacketPtr pkt)
260{
261    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
262    if (offset < PCI_DEVICE_SPECIFIC) {
263        PciDevice::writeConfig(pkt);
264    } else {
265        switch (pkt->getSize()) {
266          case sizeof(uint8_t):
267            switch (offset) {
268              case DeviceTiming:
269                deviceTiming = pkt->getLE<uint8_t>();
270                break;
271              case UDMAControl:
272                udmaControl = pkt->getLE<uint8_t>();
273                break;
274              case IDEConfig:
275                replaceBits(ideConfig, 7, 0, pkt->getLE<uint8_t>());
276                break;
277              case IDEConfig + 1:
278                replaceBits(ideConfig, 15, 8, pkt->getLE<uint8_t>());
279                break;
280              default:
281                panic("Invalid PCI configuration write "
282                        "for size 1 offset: %#x!\n", offset);
283            }
284            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
285                    offset, (uint32_t)pkt->getLE<uint8_t>());
286            break;
287          case sizeof(uint16_t):
288            switch (offset) {
289              case UDMAControl:
290                udmaControl = pkt->getLE<uint16_t>();
291                break;
292              case PrimaryTiming:
293                primaryTiming = pkt->getLE<uint16_t>();
294                break;
295              case SecondaryTiming:
296                secondaryTiming = pkt->getLE<uint16_t>();
297                break;
298              case UDMATiming:
299                udmaTiming = pkt->getLE<uint16_t>();
300                break;
301              case IDEConfig:
302                ideConfig = pkt->getLE<uint16_t>();
303                break;
304              default:
305                panic("Invalid PCI configuration write "
306                        "for size 2 offset: %#x!\n",
307                        offset);
308            }
309            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
310                    offset, (uint32_t)pkt->getLE<uint16_t>());
311            break;
312          case sizeof(uint32_t):
313            switch (offset) {
314              case PrimaryTiming:
315                primaryTiming = pkt->getLE<uint32_t>();
316                break;
317              case IDEConfig:
318                ideConfig = pkt->getLE<uint32_t>();
319                break;
320              default:
321                panic("Write of unimplemented PCI config. register: %x\n", offset);
322            }
323            break;
324          default:
325            panic("invalid access size(?) for PCI configspace!\n");
326        }
327        pkt->makeAtomicResponse();
328    }
329
330    /* Trap command register writes and enable IO/BM as appropriate as well as
331     * BARs. */
332    switch(offset) {
333      case PCI0_BASE_ADDR0:
334        if (BARAddrs[0] != 0)
335            primary.cmdAddr = BARAddrs[0];
336        break;
337
338      case PCI0_BASE_ADDR1:
339        if (BARAddrs[1] != 0)
340            primary.ctrlAddr = BARAddrs[1];
341        break;
342
343      case PCI0_BASE_ADDR2:
344        if (BARAddrs[2] != 0)
345            secondary.cmdAddr = BARAddrs[2];
346        break;
347
348      case PCI0_BASE_ADDR3:
349        if (BARAddrs[3] != 0)
350            secondary.ctrlAddr = BARAddrs[3];
351        break;
352
353      case PCI0_BASE_ADDR4:
354        if (BARAddrs[4] != 0)
355            bmiAddr = BARAddrs[4];
356        break;
357
358      case PCI_COMMAND:
359        DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
360        ioEnabled = (config.command & htole(PCI_CMD_IOSE));
361        bmEnabled = (config.command & htole(PCI_CMD_BME));
362        break;
363    }
364    return configDelay;
365}
366
367void
368IdeController::Channel::accessCommand(Addr offset,
369        int size, uint8_t *data, bool read)
370{
371    const Addr SelectOffset = 6;
372    const uint8_t SelectDevBit = 0x10;
373
374    if (!read && offset == SelectOffset)
375        select(*data & SelectDevBit);
376
377    if (selected == NULL) {
378        assert(size == sizeof(uint8_t));
379        *data = 0;
380    } else if (read) {
381        selected->readCommand(offset, size, data);
382    } else {
383        selected->writeCommand(offset, size, data);
384    }
385}
386
387void
388IdeController::Channel::accessControl(Addr offset,
389        int size, uint8_t *data, bool read)
390{
391    if (selected == NULL) {
392        assert(size == sizeof(uint8_t));
393        *data = 0;
394    } else if (read) {
395        selected->readControl(offset, size, data);
396    } else {
397        selected->writeControl(offset, size, data);
398    }
399}
400
401void
402IdeController::Channel::accessBMI(Addr offset,
403        int size, uint8_t *data, bool read)
404{
405    assert(offset + size <= sizeof(BMIRegs));
406    if (read) {
407        memcpy(data, (uint8_t *)&bmiRegs + offset, size);
408    } else {
409        switch (offset) {
410          case BMICommand:
411            {
412                if (size != sizeof(uint8_t))
413                    panic("Invalid BMIC write size: %x\n", size);
414
415                BMICommandReg oldVal = bmiRegs.command;
416                BMICommandReg newVal = *data;
417
418                // if a DMA transfer is in progress, R/W control cannot change
419                if (oldVal.startStop && oldVal.rw != newVal.rw)
420                    oldVal.rw = newVal.rw;
421
422                if (oldVal.startStop != newVal.startStop) {
423                    if (selected == NULL)
424                        panic("DMA start for disk which does not exist\n");
425
426                    if (oldVal.startStop) {
427                        DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
428                        bmiRegs.status.active = 0;
429
430                        selected->abortDma();
431                    } else {
432                        DPRINTF(IdeCtrl, "Starting DMA transfer\n");
433                        bmiRegs.status.active = 1;
434
435                        selected->startDma(letoh(bmiRegs.bmidtp));
436                    }
437                }
438
439                bmiRegs.command = newVal;
440            }
441            break;
442          case BMIStatus:
443            {
444                if (size != sizeof(uint8_t))
445                    panic("Invalid BMIS write size: %x\n", size);
446
447                BMIStatusReg oldVal = bmiRegs.status;
448                BMIStatusReg newVal = *data;
449
450                // the BMIDEA bit is read only
451                newVal.active = oldVal.active;
452
453                // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
454                if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
455                    newVal.intStatus = 0; // clear the interrupt?
456                } else {
457                    // Assigning two bitunion fields to each other does not
458                    // work as intended, so we need to use this temporary variable
459                    // to get around the bug.
460                    uint8_t tmp = oldVal.intStatus;
461                    newVal.intStatus = tmp;
462                }
463                if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
464                    newVal.dmaError = 0;
465                } else {
466                    uint8_t tmp = oldVal.dmaError;
467                    newVal.dmaError = tmp;
468                }
469
470                bmiRegs.status = newVal;
471            }
472            break;
473          case BMIDescTablePtr:
474            if (size != sizeof(uint32_t))
475                panic("Invalid BMIDTP write size: %x\n", size);
476            bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
477            break;
478          default:
479            if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
480                    size != sizeof(uint32_t))
481                panic("IDE controller write of invalid write size: %x\n", size);
482            memcpy((uint8_t *)&bmiRegs + offset, data, size);
483        }
484    }
485}
486
487void
488IdeController::dispatchAccess(PacketPtr pkt, bool read)
489{
490    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
491         panic("Bad IDE read size: %d\n", pkt->getSize());
492
493    if (!ioEnabled) {
494        pkt->makeAtomicResponse();
495        DPRINTF(IdeCtrl, "io not enabled\n");
496        return;
497    }
498
499    Addr addr = pkt->getAddr();
500    int size = pkt->getSize();
501    uint8_t *dataPtr = pkt->getPtr<uint8_t>();
502
503    if (addr >= primary.cmdAddr &&
504            addr < (primary.cmdAddr + primary.cmdSize)) {
505        addr -= primary.cmdAddr;
506        // linux may have shifted the address by ioShift,
507        // here we shift it back, similarly for ctrlOffset.
508        addr >>= ioShift;
509        primary.accessCommand(addr, size, dataPtr, read);
510    } else if (addr >= primary.ctrlAddr &&
511               addr < (primary.ctrlAddr + primary.ctrlSize)) {
512        addr -= primary.ctrlAddr;
513        addr += ctrlOffset;
514        primary.accessControl(addr, size, dataPtr, read);
515    } else if (addr >= secondary.cmdAddr &&
516               addr < (secondary.cmdAddr + secondary.cmdSize)) {
517        addr -= secondary.cmdAddr;
518        secondary.accessCommand(addr, size, dataPtr, read);
519    } else if (addr >= secondary.ctrlAddr &&
520               addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
521        addr -= secondary.ctrlAddr;
522        secondary.accessControl(addr, size, dataPtr, read);
523    } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
524        if (!read && !bmEnabled)
525            return;
526        addr -= bmiAddr;
527        if (addr < sizeof(Channel::BMIRegs)) {
528            primary.accessBMI(addr, size, dataPtr, read);
529        } else {
530            addr -= sizeof(Channel::BMIRegs);
531            secondary.accessBMI(addr, size, dataPtr, read);
532        }
533    } else {
534        panic("IDE controller access to invalid address: %#x\n", addr);
535    }
536
537#ifndef NDEBUG
538    uint32_t data;
539    if (pkt->getSize() == 1)
540        data = pkt->getLE<uint8_t>();
541    else if (pkt->getSize() == 2)
542        data = pkt->getLE<uint16_t>();
543    else
544        data = pkt->getLE<uint32_t>();
545    DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
546            read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
547#endif
548
549    pkt->makeAtomicResponse();
550}
551
552Tick
553IdeController::read(PacketPtr pkt)
554{
555    dispatchAccess(pkt, true);
556    return pioDelay;
557}
558
559Tick
560IdeController::write(PacketPtr pkt)
561{
562    dispatchAccess(pkt, false);
563    return pioDelay;
564}
565
566void
567IdeController::serialize(CheckpointOut &cp) const
568{
569    // Serialize the PciDevice base class
570    PciDevice::serialize(cp);
571
572    // Serialize channels
573    primary.serialize("primary", cp);
574    secondary.serialize("secondary", cp);
575
576    // Serialize config registers
577    SERIALIZE_SCALAR(primaryTiming);
578    SERIALIZE_SCALAR(secondaryTiming);
579    SERIALIZE_SCALAR(deviceTiming);
580    SERIALIZE_SCALAR(udmaControl);
581    SERIALIZE_SCALAR(udmaTiming);
582    SERIALIZE_SCALAR(ideConfig);
583
584    // Serialize internal state
585    SERIALIZE_SCALAR(ioEnabled);
586    SERIALIZE_SCALAR(bmEnabled);
587    SERIALIZE_SCALAR(bmiAddr);
588    SERIALIZE_SCALAR(bmiSize);
589}
590
591void
592IdeController::Channel::serialize(const std::string &base,
593                                  CheckpointOut &cp) const
594{
595    paramOut(cp, base + ".cmdAddr", cmdAddr);
596    paramOut(cp, base + ".cmdSize", cmdSize);
597    paramOut(cp, base + ".ctrlAddr", ctrlAddr);
598    paramOut(cp, base + ".ctrlSize", ctrlSize);
599    uint8_t command = bmiRegs.command;
600    paramOut(cp, base + ".bmiRegs.command", command);
601    paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
602    uint8_t status = bmiRegs.status;
603    paramOut(cp, base + ".bmiRegs.status", status);
604    paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
605    paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
606    paramOut(cp, base + ".selectBit", selectBit);
607}
608
609void
610IdeController::unserialize(CheckpointIn &cp)
611{
612    // Unserialize the PciDevice base class
613    PciDevice::unserialize(cp);
614
615    // Unserialize channels
616    primary.unserialize("primary", cp);
617    secondary.unserialize("secondary", cp);
618
619    // Unserialize config registers
620    UNSERIALIZE_SCALAR(primaryTiming);
621    UNSERIALIZE_SCALAR(secondaryTiming);
622    UNSERIALIZE_SCALAR(deviceTiming);
623    UNSERIALIZE_SCALAR(udmaControl);
624    UNSERIALIZE_SCALAR(udmaTiming);
625    UNSERIALIZE_SCALAR(ideConfig);
626
627    // Unserialize internal state
628    UNSERIALIZE_SCALAR(ioEnabled);
629    UNSERIALIZE_SCALAR(bmEnabled);
630    UNSERIALIZE_SCALAR(bmiAddr);
631    UNSERIALIZE_SCALAR(bmiSize);
632}
633
634void
635IdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp)
636{
637    paramIn(cp, base + ".cmdAddr", cmdAddr);
638    paramIn(cp, base + ".cmdSize", cmdSize);
639    paramIn(cp, base + ".ctrlAddr", ctrlAddr);
640    paramIn(cp, base + ".ctrlSize", ctrlSize);
641    uint8_t command;
642    paramIn(cp, base +".bmiRegs.command", command);
643    bmiRegs.command = command;
644    paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
645    uint8_t status;
646    paramIn(cp, base + ".bmiRegs.status", status);
647    bmiRegs.status = status;
648    paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
649    paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
650    paramIn(cp, base + ".selectBit", selectBit);
651    select(selectBit);
652}
653
654IdeController *
655IdeControllerParams::create()
656{
657    return new IdeController(this);
658}
659