OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [arm/] [aim711/] [current/] [src/] [aim711_misc.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      aim711_misc.c
4
//
5
//      HAL misc board support code for ARM Industrial Module AIM 711
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas, jskov, r.cassebohm
44
//               Michael Checky <Michael_Checky@ThermoKing.com>
45
//               Grant Edwards <grante@visi.com>
46
// Date:         2001-07-31
47
// Purpose:      HAL board support
48
// Description:  Implementations of HAL board interfaces
49
//
50
//####DESCRIPTIONEND####
51
//
52
//========================================================================*/
53
 
54
#include <pkgconf/hal.h>
55
 
56
#include <cyg/infra/cyg_type.h>         // base types
57
#include <cyg/infra/cyg_trac.h>         // tracing macros
58
#include <cyg/infra/cyg_ass.h>          // assertion macros
59
#include <cyg/infra/diag.h>             // diag_printf()
60
 
61
#include <cyg/hal/hal_io.h>             // IO macros
62
#include <cyg/hal/hal_arch.h>           // Register state info
63
#include <cyg/hal/hal_diag.h>
64
#include <cyg/hal/hal_cache.h>
65
#include <cyg/hal/hal_intr.h>           // necessary?
66
#include <cyg/hal/hal_if.h>             // calling interface
67
#include <cyg/hal/hal_misc.h>           // helper functions
68
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
69
#include <cyg/hal/drv_api.h>            // HAL ISR support
70
#endif
71
 
72
#include <pkgconf/system.h>
73
 
74
#ifndef MIN
75
#define MIN(_x_,_y_) ((_x_) < (_y_) ? (_x_) : (_y_))
76
#endif
77
#ifndef MAX
78
#define MAX(_x_,_y_) ((_x_) > (_y_) ? (_x_) : (_y_))
79
#endif
80
 
81
//======================================================================
82
// Use Timer0 for kernel clock
83
 
84
static cyg_uint32 _period;
85
 
86
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
87
#if 0 // Not supported yet
88
static cyg_interrupt abort_interrupt;
89
static cyg_handle_t  abort_interrupt_handle;
90
 
91
// This ISR is called only for the Abort button interrupt
92
static int
93
ks32c_abort_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
94
{
95
    cyg_hal_user_break((CYG_ADDRWORD*)regs);
96
    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EXT2);
97
    return 0;  // No need to run DSR
98
}
99
#endif
100
#endif
101
 
102
void hal_clock_initialize(cyg_uint32 period)
103
{
104
    cyg_uint32 tmod, clkcon;
105
 
106
    // Disable timer 0
107
    HAL_READ_UINT32(KS32C_TMOD, tmod);
108
    tmod &= ~(KS32C_TMOD_TE0);
109
    HAL_WRITE_UINT32(KS32C_TMOD, 0);
110
 
111
    tmod &= ~(KS32C_TMOD_TMD0 | KS32C_TMOD_TCLR0);
112
    tmod |= KS32C_TMOD_TE0;
113
 
114
    // Set counter
115
    HAL_READ_UINT32(KS32C_CLKCON, clkcon);
116
    period = period/((clkcon & 0xffff) + 1);
117
    HAL_WRITE_UINT32(KS32C_TDATA0, period);
118
 
119
    // And enable timer
120
    HAL_WRITE_UINT32(KS32C_TMOD, tmod);
121
 
122
    _period = period;
123
 
124
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
125
#if 0 // Not supported yet
126
    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EXT2,
127
                             99,           // Priority
128
                             0,            // Data item passed to interrupt handler
129
                             ks32c_abort_isr,
130
                             0,
131
                             &abort_interrupt_handle,
132
                             &abort_interrupt);
133
    cyg_drv_interrupt_attach(abort_interrupt_handle);
134
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EXT2);
135
#endif
136
#endif
137
}
138
 
139
void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
140
{
141
    _period = period;
142
}
143
 
144
void hal_clock_read(cyg_uint32 *pvalue)
145
{
146
    cyg_uint32 value;
147
 
148
    HAL_READ_UINT32(KS32C_TCNT0, value);
149
    *pvalue = _period - value;
150
}
151
 
152
static void
153
hal_ks32c_i2c_init(void);
154
 
155
//======================================================================
156
// Interrupt controller stuff
157
 
158
void hal_hardware_init(void)
159
{
160
    cyg_uint32 intmask, syscfg, val;
161
 
162
    // Setup external IO timing
163
    // Timing for Ext0 is for external 16550 UART, all other are default values
164
    val = ( KS32C_EXTACON_INIT(1,1,3,0) << KS32C_EXTACON0_EXT0_shift ) \
165
            | ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON0_EXT1_shift );
166
    HAL_WRITE_UINT32(KS32C_EXTACON0, val);
167
    val = ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON1_EXT2_shift ) \
168
            | ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON1_EXT3_shift );
169
    HAL_WRITE_UINT32(KS32C_EXTACON1, val);
170
 
171
    // Setup GPIO ports
172
    HAL_READ_UINT32(KS32C_IOPMOD, val);
173
    val |= (AIM711_GPIO_DOUT0_DAK0|AIM711_GPIO_DOUT1_DAK1 \
174
            |AIM711_GPIO_DOUT2_TO0|AIM711_GPIO_DOUT3_TO1 \
175
            |AIM711_GPIO_POWERLED);
176
    HAL_WRITE_UINT32(KS32C_IOPMOD, val);
177
 
178
    // Make Power LED on
179
    AIM711_GPIO_SET(AIM711_GPIO_POWERLED);
180
 
181
    // Enable XIRQ0 for external 16550 UART
182
    HAL_READ_UINT32(KS32C_IOPCON, val);
183
    val &= ~( KS32C_IOPCON_XIRQ_MASK << KS32C_IOPCON_XIRQ0_shift );
184
    val |= ( KS32C_IOPCON_XIRQ_LEVEL|KS32C_IOPCON_XIRQ_AKTIV_HI| \
185
            KS32C_IOPCON_XIRQ_ENABLE ) << KS32C_IOPCON_XIRQ0_shift ;
186
    HAL_WRITE_UINT32(KS32C_IOPCON, val);
187
 
188
    // Set up eCos/ROM interfaces
189
    hal_if_init();
190
 
191
    // Enable cache
192
    HAL_READ_UINT32(KS32C_SYSCFG, syscfg);
193
    syscfg &= ~KS32C_SYSCFG_CM_MASK;
194
    syscfg |= KS32C_SYSCFG_CM_0R_8C|KS32C_SYSCFG_WE;
195
    HAL_WRITE_UINT32(KS32C_SYSCFG, syscfg);
196
    HAL_UCACHE_INVALIDATE_ALL();
197
    HAL_UCACHE_ENABLE();
198
 
199
    // Setup I2C bus
200
    hal_ks32c_i2c_init();
201
 
202
    // Clear global interrupt mask bit
203
    HAL_READ_UINT32(KS32C_INTMSK, intmask);
204
    intmask &= ~KS32C_INTMSK_GLOBAL;
205
    HAL_WRITE_UINT32(KS32C_INTMSK, intmask);
206
}
207
 
208
// This routine is called to respond to a hardware interrupt (IRQ).  It
209
// should interrogate the hardware and return the IRQ vector number.
210
 
211
int hal_IRQ_handler(void)
212
{
213
    // Do hardware-level IRQ handling
214
    cyg_uint32 irq_status;
215
    HAL_READ_UINT32(KS32C_INTOFFSET_IRQ, irq_status);
216
    irq_status = irq_status / 4;
217
    if (CYGNUM_HAL_ISR_MAX >= irq_status)
218
        return irq_status;
219
    // It's a bit bogus to test for FIQs after IRQs, but we use the
220
    // latter more, so don't impose the overhead of checking for FIQs
221
    HAL_READ_UINT32(KS32C_INTOFFSET_FIQ, irq_status);
222
    irq_status = irq_status / 4;
223
    if (CYGNUM_HAL_ISR_MAX >= irq_status)
224
        return irq_status;
225
    return CYGNUM_HAL_INTERRUPT_NONE;
226
}
227
 
228
// -------------------------------------------------------------------------
229
//
230
// Interrupt control
231
//
232
 
233
void hal_interrupt_mask(int vector)
234
{
235
    cyg_uint32 mask, old_mask;
236
    HAL_READ_UINT32(KS32C_INTMSK, mask);
237
    old_mask = mask;
238
    mask |= (1<<vector);
239
    HAL_WRITE_UINT32(KS32C_INTMSK, mask);
240
}
241
 
242
void hal_interrupt_unmask(int vector)
243
{
244
    cyg_uint32 mask, old_mask;
245
    HAL_READ_UINT32(KS32C_INTMSK, mask);
246
    old_mask = mask;
247
    mask &= ~(1<<vector);
248
    HAL_WRITE_UINT32(KS32C_INTMSK, mask);
249
}
250
 
251
void hal_interrupt_acknowledge(int vector)
252
{
253
    HAL_WRITE_UINT32(KS32C_INTPND, (1<<vector));
254
}
255
 
256
void hal_interrupt_configure(int vector, int level, int up)
257
{
258
}
259
 
260
void hal_interrupt_set_level(int vector, int level)
261
{
262
}
263
 
264
void hal_show_IRQ(int vector, int data, int handler)
265
{
266
}
267
 
268
// -------------------------------------------------------------------------
269
//
270
// Delay for some number of micro-seconds
271
//
272
void hal_delay_us(cyg_int32 usecs)
273
{
274
    cyg_uint32 count;
275
    cyg_uint32 ticks = ((CYGNUM_HAL_RTC_PERIOD*CYGNUM_HAL_RTC_DENOMINATOR)/1000000) * usecs;
276
    cyg_uint32 tmod;
277
 
278
    // Disable timer 1
279
    HAL_READ_UINT32(KS32C_TMOD, tmod);
280
    tmod &= ~(KS32C_TMOD_TE1);
281
    HAL_WRITE_UINT32(KS32C_TMOD, tmod);
282
 
283
    tmod &= ~(KS32C_TMOD_TMD1 | KS32C_TMOD_TCLR1);
284
    tmod |= KS32C_TMOD_TE1;
285
 
286
    // Clear pending flag
287
    HAL_WRITE_UINT32(KS32C_INTPND, (1 << CYGNUM_HAL_INTERRUPT_TIMER1));
288
 
289
    // Set counter
290
    HAL_WRITE_UINT32(KS32C_TDATA1, ticks);
291
 
292
    // And enable timer
293
    HAL_WRITE_UINT32(KS32C_TMOD, tmod);
294
 
295
    // Wait for timer to underflow. Can't test the timer completion
296
    // bit without actually enabling the interrupt. So instead watch
297
    // the counter.
298
    ticks /= 2;                         // wait for this threshold
299
 
300
    // Wait till timer counts below threshold
301
    do {
302
        HAL_READ_UINT32(KS32C_TCNT1, count);
303
    } while (count >= ticks);
304
    // then wait for it to be reloaded
305
    do {
306
        HAL_READ_UINT32(KS32C_TCNT1, count);
307
    } while (count < ticks);
308
 
309
    // Then disable timer 1 again
310
    tmod &= ~KS32C_TMOD_TE1;
311
    HAL_WRITE_UINT32(KS32C_TMOD, tmod);
312
}
313
 
314
// -------------------------------------------------------------------------
315
//
316
// To reset the AIM 711, set P3 to low, which is connected to the reset
317
// logic 
318
//
319
void hal_reset(void)
320
{
321
    cyg_uint32 value;
322
    CYG_INTERRUPT_STATE old;
323
 
324
    CYGACC_CALL_IF_DELAY_US(100000);
325
 
326
    // Set P3 to output
327
    HAL_READ_UINT32(KS32C_IOPMOD, value);
328
    value |= AIM711_GPIO_RESET;
329
    HAL_WRITE_UINT32(KS32C_IOPMOD, value);
330
 
331
    // Set P3 to low
332
    AIM711_GPIO_CLR(AIM711_GPIO_RESET);
333
 
334
    HAL_DISABLE_INTERRUPTS(old);
335
    while (1)
336
    ;
337
}
338
 
339
//----------------------------------------------------------------------
340
//
341
// I2C Support
342
//
343
 
344
#include <string.h>
345
#include <cyg/hal/drv_api.h>
346
 
347
#ifdef CYGPKG_ERROR
348
#include <errno.h>
349
#define I2C_STATUS_SUCCESS      (ENOERR)
350
#define I2C_STATUS_MUTEX        (-EINTR)
351
#define I2C_STATUS_BUSY         (-EBUSY)
352
#define I2C_STATUS_ADDR_NAK     (-1000)
353
#define I2C_STATUS_DATA_NAK     (-1001)
354
#else
355
#define I2C_STATUS_SUCCESS      (0)
356
#define I2C_STATUS_MUTEX        (-1)
357
#define I2C_STATUS_BUSY         (-1)
358
#define I2C_STATUS_ADDR_NAK     (-1)
359
#define I2C_STATUS_DATA_NAK     (-1)
360
#endif
361
 
362
static cyg_drv_mutex_t i2c_mutex;
363
 
364
//  Initialize the I2C bus controller.
365
static void
366
hal_ks32c_i2c_init(void)
367
{
368
    cyg_uint32 prescale = KS32C_I2C_FREQ(100000);
369
 
370
    // reset the bus controller
371
    HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_RESET);
372
 
373
    // set the bus frequency
374
    HAL_WRITE_UINT32(KS32C_I2CPS, prescale);
375
 
376
    cyg_drv_mutex_init(&i2c_mutex);
377
}
378
 
379
#define RETURN(_x_) \
380
    CYG_MACRO_START                             \
381
    diag_printf("%s: line %d error=%d\n",__FUNCTION__,__LINE__,(_x_)); \
382
    return (_x_); \
383
    CYG_MACRO_END
384
 
385
//  Transfer the I2C messages.
386
int
387
hal_ks32c_i2c_transfer(cyg_uint32 nmsg, hal_ks32c_i2c_msg_t* pmsgs)
388
{
389
    cyg_uint32 i2ccon;
390
 
391
    // serialize access to the I2C bus
392
    if (!cyg_drv_mutex_lock(&i2c_mutex))
393
    {
394
        RETURN(I2C_STATUS_MUTEX);
395
    }
396
 
397
    // is the bus free ?
398
    do
399
    {
400
        HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
401
    } while (i2ccon & KS32C_I2C_CON_BUSY);
402
 
403
    // transfer the messages
404
    for (; nmsg > 0; --nmsg, ++pmsgs)
405
    {
406
        // generate the start condition
407
        HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_START);
408
 
409
        // send the device address
410
        HAL_WRITE_UINT32(KS32C_I2CBUF, pmsgs->devaddr);
411
        do
412
        {
413
            HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
414
        } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
415
 
416
        // check if the slave ACK'ed the device address
417
        if (i2ccon & KS32C_I2C_CON_LRB)
418
        {
419
            // generate the stop condition
420
            HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
421
            cyg_drv_mutex_unlock(&i2c_mutex);
422
            RETURN(I2C_STATUS_ADDR_NAK);
423
        }
424
 
425
        // read the message ?
426
        if (pmsgs->devaddr & KS32C_I2C_RD)
427
        {
428
            cyg_uint8* pbuf = pmsgs->pbuf;
429
            cyg_uint32 bufsize = pmsgs->bufsize;
430
            cyg_uint32 i2cbuf;
431
 
432
            // read more than one byte ?
433
            if (--bufsize > 0)
434
            {
435
                // enable ACK
436
                HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_ACK);
437
 
438
                while (bufsize-- > 0)
439
                {
440
                    do
441
                    {
442
                        HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
443
                    } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
444
 
445
                    // read the data byte
446
                    HAL_READ_UINT32(KS32C_I2CBUF, i2cbuf);
447
                    *pbuf++ = i2cbuf;
448
                }
449
            }
450
 
451
            // disable ACK
452
            HAL_WRITE_UINT32(KS32C_I2CCON, 0);
453
            do
454
            {
455
                HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
456
            } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
457
 
458
            // read the data byte
459
            HAL_READ_UINT32(KS32C_I2CBUF, i2cbuf);
460
            *pbuf++ = i2cbuf;
461
        }
462
 
463
        // write the message
464
        else
465
        {
466
            cyg_uint32 i;
467
 
468
            for (i = 0; i < pmsgs->bufsize; ++i)
469
            {
470
                HAL_WRITE_UINT32(KS32C_I2CBUF, pmsgs->pbuf[i]);
471
                do
472
                {
473
                    HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
474
                } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
475
 
476
                // check if the slave ACK'ed the data byte
477
                if (i2ccon & KS32C_I2C_CON_LRB)
478
                {
479
                    // generate the stop condition
480
                    HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
481
                    cyg_drv_mutex_unlock(&i2c_mutex);
482
                    RETURN(I2C_STATUS_DATA_NAK);
483
                }
484
            }
485
        }
486
 
487
        // generate a restart condition ?
488
        if (nmsg > 1)
489
        {
490
            HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_RESTART);
491
        }
492
    }
493
 
494
    // generate the stop condition
495
    HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
496
 
497
    cyg_drv_mutex_unlock(&i2c_mutex);
498
    return I2C_STATUS_SUCCESS;
499
}
500
 
501
//----------------------------------------------------------------------
502
//
503
// EEPROM Support
504
//
505
 
506
int hal_aim711_eeprom_write(cyg_uint8 *buf, int offset, int len)
507
{
508
    cyg_uint8 addr_page[1 + AIM711_EEPROM_PAGESIZE];
509
    cyg_uint8 const* pbufbyte = (cyg_uint8 const*)buf;
510
    hal_ks32c_i2c_msg_t msg;
511
    cyg_uint8 addr;
512
    cyg_uint32 bufsize;
513
 
514
    if (offset > AIM711_EEPROM_SIZE)
515
        RETURN(-1);
516
 
517
    if (len > (AIM711_EEPROM_SIZE - offset))
518
        len = (AIM711_EEPROM_SIZE - offset);
519
 
520
    addr = offset;
521
    bufsize = len;
522
 
523
    msg.devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_WR;
524
    msg.pbuf = addr_page;
525
 
526
    while (bufsize > 0)
527
    {
528
        cyg_uint32 nbytes;
529
        int status;
530
 
531
        // write at most a page at a time
532
        nbytes = MIN(bufsize, AIM711_EEPROM_PAGESIZE);
533
 
534
        // don't cross a page boundary
535
        if (addr%AIM711_EEPROM_PAGESIZE)
536
        {
537
            nbytes = MIN(nbytes, AIM711_EEPROM_PAGESIZE - addr%AIM711_EEPROM_PAGESIZE);
538
        }
539
 
540
        // build the write message
541
        addr_page[0] = addr;
542
        memcpy(&addr_page[1], pbufbyte, nbytes);
543
        msg.bufsize = nbytes + 1;
544
        addr += nbytes;
545
        pbufbyte += nbytes;
546
        bufsize -= nbytes;
547
 
548
        // transfer the message
549
        status = hal_ks32c_i2c_transfer(1, &msg);
550
        if (status != I2C_STATUS_SUCCESS)
551
        {
552
            RETURN(status);
553
        }
554
 
555
        // delay 10 msec
556
        CYGACC_CALL_IF_DELAY_US(10000);
557
    }
558
 
559
    return len;
560
}
561
 
562
int hal_aim711_eeprom_read(cyg_uint8 *buf, int offset, int len)
563
{
564
    hal_ks32c_i2c_msg_t msgs[2];
565
    int status;
566
    cyg_uint8 toffset;
567
 
568
    if (offset > AIM711_EEPROM_SIZE)
569
        RETURN(-1);
570
 
571
    if (len > (AIM711_EEPROM_SIZE - offset))
572
        len = (AIM711_EEPROM_SIZE - offset);
573
 
574
    toffset = offset;
575
 
576
    // write message to set the address
577
    msgs[0].devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_WR;
578
    msgs[0].pbuf = &toffset;
579
    msgs[0].bufsize = sizeof(toffset);
580
 
581
    // read message
582
    msgs[1].devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_RD;
583
    msgs[1].pbuf = buf;
584
    msgs[1].bufsize = len;
585
 
586
    // transfer the messages
587
    status = hal_ks32c_i2c_transfer(2, msgs);
588
 
589
    if (status < 0)
590
        RETURN(status);
591
 
592
    return len;
593
}
594
 
595
//-----------------------------------------------------------------------------
596
//
597
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.