找回密码
 注册
关于网站域名变更的通知
查看: 258|回复: 2
打印 上一主题 下一主题

有偿求ADI公司AD1933 LINUX平台驱动

[复制链接]
  • TA的每日心情
    擦汗
    2021-8-10 15:35
  • 签到天数: 140 天

    [LV.7]常住居民III

    跳转到指定楼层
    1#
    发表于 2021-12-23 11:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
    有偿求ADI公司AD1933 LINUX平台通过SPI配置AD1933,通过SAI接口(4路数据)传输音频信号
    0 O' }$ |. x' |+ o) A  }( D3 h5 n

    该用户从未签到

    2#
    发表于 2021-12-23 13:54 | 只看该作者
    1、驱动源代码
    $ \( X4 ~0 B8 k5 ?7 U! m
    7 ^6 \' k- b, p0 b) i

    ' I0 ^9 w/ b$ b#include <linux/module.h>
    2 |: ]- n/ c/ X: ?#include <linux/kernel.h>2 g! e1 G2 t8 x5 s* h- c' E
    #include <linux/fs.h>
    : p  y" u; m9 L# k4 @#include <linux/init.h>
    - H5 q$ Q) d! Z+ I#include <linux/device.h>4 J9 ~0 m& p" Y% x
    #include <linux/miscdevice.h>
    0 n! A5 F  u% |7 o#include <linux/delay.h>
    ' K; P' x' m0 h* ?# c3 c" W! g#include <linux/mm.h>
    4 b$ Z0 S# e* `* p3 m. A( D#include <asm/irq.h>2 C$ M) p+ @% J3 A
    #include <asm/arch/regs-timer.h>: D2 l/ @- E  p! I5 W4 I3 f
    #include <asm/arch/regs-adc.h>
    * Z% r& b4 g4 |#include <asm/arch/regs-gpio.h>
    ( a0 t: l7 B$ r6 a9 t#include <asm/arch/map.h>
    - [1 h7 Z( S( T4 _6 h  ]( m: a#include <asm/arch/regs-irq.h>+ ?7 Y3 k2 z6 `+ t
    #include <asm/io.h>0 L" h; B) o4 X! N) g
    #include <asm/hardware.h>
    + D. W0 u9 [8 J2 u#include <asm/uaccess.h>
    1 d/ z3 T. r' r4 q* F8 C#include <asm/system.h>
    + t  `# x2 p8 x! x& {  P2 W#include <linux/errno.h>- P2 L( c/ {* d" B, w4 w2 ?
    #include <linux/slab.h>* x/ |) P% L0 S
    #include <linux/input.h>
    5 @! A& p. u7 {1 h; j' q#include <linux/serio.h>+ n$ e/ X& R! R) L& L9 f
    #include <linux/clk.h># R. ?6 X6 m7 k* u' _( @( u
    #include <linux/cdev.h># a. i# R2 l& T1 ^" F

    % R( J+ R9 [0 k7 j/ `% L% f9 `

    ) F5 ]9 p8 |0 d0 t7 d: T
    8 e  D4 i! F/ F: r1 I

    + H# r  ^4 ?+ }1 d3 X6 w#define ADC_WRITE(ch, prescale)    ((ch) << 16 | (prescale))0 j8 u! e+ M+ X. c  r$ {0 v

    6 j, ~+ k& v" m3 a
    $ s- N  b+ d2 {8 B9 b
    #define ADC_WRITE_GETCH(data)    (((data) >> 16) & 0x7)
    . v5 a* l6 H( q#define ADC_WRITE_GETPRE(data)    ((data) & 0xff); K: L, K$ g1 _; j4 I! u4 ^

    " z3 e6 w  A. b, k
    ' S) \1 n. R; p6 m/ c# v
    #define DEVICE_NAME    "adc"1 T% j& ~/ q2 `. U/ O% X2 J8 F

    6 c/ F* Q( s% n/ _
    0 L7 E7 U. q  T6 f0 Q
    static void __iomem *base_addr;
    / \4 `* v' I  c( ^: c- O' Z% D- z0 M, v5 D: F8 K; k  H' w
    0 E. K9 ?( ~. [5 V  t' S
    typedef struct {                    //adc转换的设备结构体
    1 `5 U2 a3 o8 x    wait_queue_head_t wait; //等待队列) Z# y0 Q! i2 B7 V0 n
        int channel;            //ADC转换通道8 i6 ^# M0 @6 k8 i) }2 D
        int prescale;
    % ?* ^9 n& n. h6 s}ADC_DEV;
    * N7 {1 `: |0 X8 Q6 P( ?. W  K: D$ D# M' M+ ]6 _6 p

    ; F3 i! L$ n+ `: L9 |7 {( N8 B2 {DECLARE_MUTEX(ADC_LOCK); //定义互斥信号量
    9 Z5 C. B* M9 j1 u% ]' hstatic int ADC_OK = 0;8 c; F  _6 `4 L# v' e) Q  |
    # t1 D9 Y  O# a) c! \+ m& b9 E4 u
    ' _. i5 s7 @7 w; z' }
    static ADC_DEV adcdev;
    7 x7 g) v4 }2 Mstatic volatile int ev_adc = 0;. b1 ]. v% G6 C. |+ ?
    static int adc_data;3 z9 ^! B/ I$ D2 Y8 J

    $ ~8 T. q# m/ y7 f7 y1 g
    / N% [1 \$ l$ @: G1 P9 q; r
    static struct clk    *adc_clock;
    ) t* u. F' a( _  L; x) |0 H" d7 y* ?9 X+ N9 m; \- {

    4 l& H* L( J! }* [) ^#define ADCCON     (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))    //ADC control8 t( D  ~5 @7 |& A/ G
    #define ADCTSC     (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))    //ADC touch screen control
    # R4 p1 ~" {2 z& W- C! I#define ADCDLY     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))    //ADC start or Interval Delay
    . q& ]5 @( ^1 I& c1 x% O#define ADCDAT0     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0))    //ADC conversion data 0) a' W( b, f) ~) T6 j3 |
    #define ADCDAT1     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1))    //ADC conversion data 1
    7 W' A1 A2 `. S7 t#define ADCUPDN     (*(volatile unsigned long *)(base_addr + 0x14))        //Stylus Up/Down interrupt status% k' I' R6 I" k( i
    $ P4 o  Y5 x1 `3 X1 a& ^) s3 T; z$ d

    $ n5 r, A+ P( Z; m0 N#define PRESCALE_DIS        (0 << 14)
    - i# b/ u- y! O/ v#define PRESCALE_EN        (1 << 14)   //使能预分频/ \3 {- _% K/ t! A5 f8 L3 C0 w
    #define PRSCVL(x)            ((x) << 6)//设定的预分频值
    % j+ H5 @: E" A! s& O+ r$ ^#define ADC_INPUT(x)        ((x) << 3)  //选择ADC转换通道
    . s) l) s2 u% ~! g/ S! m2 H6 w5 C#define ADC_START        (1 << 0)   //    启动ADC转换
    ; S! A4 ~* b! B  [& d#define ADC_ENDCVT        (1 << 15)
    5 d6 `" y- c: S$ E8 J) M+ g4 ]; f- P" O
    " F( E! ^1 a& K6 y6 a/ }5 B
    //AD转换中断处理函数
    ; k: }: J- y" hstatic irqreturn_t adcdone_int_handler(int irq, void *dev_id)2 Y' Q2 F) t9 S5 f/ m9 J& J
    {undefined
    $ }* m; w: R: i6 c3 t/ v! Z    if (ADC_OK)
    0 V. W6 n, t( X/ _3 z: ]    {undefined
    4 v5 O! [) a& r- g. \4 S% v* j# D        adc_data = ADCDAT0 & 0x3ff; //提取AD转换后的数据
    5 s& a; T; P! R" S2 L& J3 r+ C7 a% A8 H$ u

    / A% }) O; [' o5 h9 ]4 h( `        ev_adc = 1;  //转换结束唤醒等待的进程
    & Q3 P  K1 t/ b0 }; s  I        wake_up_interruptible(&adcdev.wait);
    8 d  e3 K6 }- X$ G: O/ W" G+ K    }
    1 h' F& l0 q  D7 W' [* y. F2 N, ^8 p

    7 g' @( P% S" D. b" _' a) C    return IRQ_HANDLED;7 y, J7 T! F1 Z" i; Q$ L
    }9 f' }* _3 ^* @8 Y
    0 i' G' X: D2 [
    * l+ T/ f8 h, r( R$ B, B  X
    static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)$ ~9 F. P8 A2 t$ h- f6 d
    {undefined4 P" {0 \1 E" p* i7 s
        char str[20];
    1 ]. W9 r: g: L, n* F* b1 ~    int value;
    8 r$ \- J. u8 S" e2 M" u1 {    size_t len;
    * I$ c+ @) \/ B2 X, l3 v3 m    if (down_trylock(&ADC_LOCK) == 0) //获得信号量 :获得不到信号量不会阻塞6 @9 D2 [/ T1 h
        {undefined( g; k( O. h' v. a% Q) I/ s; u
            ADC_OK = 1;//启动AD转换0 I' n" S( z+ R/ I1 |1 Q3 T$ l+ n
            ADCCON = PRESCALE_EN | PRSCVL(adcdev.prescale) | ADC_INPUT((adcdev.channel)) ;* W+ Y6 ^" Z: m' _- T" B/ K
            //使能预分频    设置预分频值  选择ADC转换通道5 z3 k( ^2 m/ x2 D3 h
            ADCCON |= ADC_START; //启动AD转换
    4 b, v* \1 W5 \        8 E/ s7 F; t- P
            wait_event_interruptible(adcdev.wait, ev_adc);  //阻塞等待AD转换" W. t; T/ }- `7 v& L
    ( p, R1 H9 t- e+ \9 D. k/ Z
    . i" N" j) V5 Z1 u6 {
            ev_adc = 0;//清除转换标志位, @) U! k8 p7 \- Q( D& `2 R0 f" p
    , s. C3 `; Y% A0 ?
    7 f$ V) o4 C- P2 |0 A4 ]
    //        printk("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);& e% j. ]& _; {6 F$ l. c
    ; I  r9 t5 Q/ d7 b! r
    ' |- P% r3 {# \1 K/ ~
            value = adc_data; //AD转换的数据
    3 G" ~6 y7 c. ~$ X" [5 E        sprintf(str,"%5d", adc_data);//数据转换0 a( A$ p5 H$ K2 D6 F& v& h& \
            //copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));
    * {: S$ U/ f' H+ ~* q
    9 W+ U8 E- j5 ]* b! c7 v
    6 e. g% f- {- D% s4 V2 E( N
            ADC_OK = 0;
    , o8 a0 c* a  m( s        up(&ADC_LOCK);//释放信号量& N- F# M" d1 d
        }
    . W1 a$ `% k$ F3 |0 K6 U! @4 u    else& F) S, x8 q& g/ h/ H  @7 Z
        {undefined+ u: v  a1 i  X+ J& a1 d3 S
            value = -1;8 z  N: ^; b% F6 r  F8 t5 K# c
        }
    + B* ^5 X# Z& r# W* c+ W. b, _5 D3 O) j: j
    9 ]9 T: T0 q: _! i4 i- d
        len = sprintf(str, "%d\n", value);
    / _5 G' w+ g7 C  x    if (count >= len)
    . n$ E0 |/ S# y7 Y- V    {undefined4 I7 M/ {$ _) b# g5 z
            int r = copy_to_user(buffer, str, len); //把AD转换数据送回用户空间
    & F7 W' ?: K* l9 \# Z+ f4 m2 n        return r ? r : len;
    ; D! \4 q2 R) i3 U6 O    }
    / a7 m/ c9 H# x$ Q    else
    ' q, a2 z3 |0 [6 z4 ]    {undefined* y; I4 t' b$ l  l, E
            return -EINVAL;2 n. o* d3 N, Q
        }5 t1 i. p5 _9 l) n/ K, o8 t) s
    }
    " M" N0 u4 s2 k/ J& j4 j- m% B" A2 {! {! k
    2 b1 x, p  u& n8 \8 P
    static int s3c2410_adc_open(struct inode *inode, struct file *filp)
    ; J! _/ F$ M' ^8 T( _{undefined8 N! ^$ x5 ]( E
        init_waitqueue_head(&(adcdev.wait));  //初始化等待队列
    9 L  m" Q  N) `: {9 Z  e& A, [% {# e/ |9 u; o
    6 q' V5 _/ L3 _5 y* M
        adcdev.channel=0;        //选择ADC转换的通道    //AIN 0 or (0~7)0 i( H5 W' r; }0 G# S: B
        adcdev.prescale=0xff;          //AD转换延时% e* L1 ^) d3 ?8 Z* |  y
    : t1 q0 K. b% T

    # H. A3 N  H5 x( T0 E+ I% u; N* B    printk( "ADC opened\n");' ]/ _( F/ w( X- x, M# @
        return 0;
    ! h0 l' f: c  {, B2 e2 L1 {! c. g}7 H* J+ R- B) o! F1 B$ I# f6 }
    ! S' N' P3 ?& T

    $ H6 R/ v6 i% u- ~static int s3c2410_adc_release(struct inode *inode, struct file *filp)! ^: z1 l2 |3 b6 b* X7 I: }. p
    {undefined/ E* u9 G' r$ k* y' C
        printk( "EmbedSky-ADC closed\n");7 l5 L: Q0 g3 q* o7 I
        return 0;' S7 G8 [" r# w) W6 W0 g
    }
    7 a( g: ]- u1 I/ L3 s4 L( B( h0 e4 q5 t

    * K2 o- U# l! o' w* bstatic struct file_operations Adc_fops = {undefined
    . R; K$ Y" z" N    owner:    THIS_MODULE,
    , V3 J& W% s7 U+ E    open:    s3c2410_adc_open,
    , `. L( n4 W! C! E    read:    s3c2410_adc_read,    2 {/ `3 Y% W3 E! X% c4 ~% C
        release:    s3c2410_adc_release,0 x* y3 O6 n  D3 H5 l
    };: m# L, x1 Y3 x/ j9 P( X* a8 _% |
    1 x# l% ]: D+ e+ {" o. u& ?

    8 \2 Z0 }" p, ^/ B! L: H# {static struct miscdevice misc = {undefined
    5 D6 z  l3 ~' |4 d: `- m    .minor = MISC_DYNAMIC_MINOR,
    ! ]) @8 E$ }; ]# v5 X2 p    .name = DEVICE_NAME,; T  ?/ [: ]% z0 G& Q
        .fops = &Adc_fops,6 C/ q5 X3 q% {& A! ~
    };# ^( Y; f# ], q: ^2 V

    ; b0 P" B2 ^5 r* g: e1 I  @
    8 Z2 l  ]" Y) L
    static char __initdata banner[] = "S3C2440 ADC\n";
    7 [1 r! B8 N- L  a% J3 r8 |" p; P
    0 u' [4 t$ B4 {, u0 _' }; h# u0 z

    * g3 F  p0 y; a, i& P+ wstatic int __init Adc_init(void); U; d, w  I8 l- n) _( e/ U, H7 |$ x
    {undefined
    2 \! D! l% W* }/ f4 e    int ret;
    $ p. X1 S2 }, Y  t: E5 E    printk(banner);8 R; m; J+ S* X; D+ k- W% D
    8 S5 e" U3 q% r

    . e; _  F1 Z9 H5 V% _! f    base_addr=ioremap(S3C2410_PA_ADC,0x20);//映射把物理地址映射为虚拟地址' x0 t- e# ~. s0 x" Y/ ^* Q
        if (base_addr == NULL)  //返回值检测
    5 \5 X. e$ {+ Y- ~    {undefined
    + X: @7 X/ c8 a- W9 p3 Y: Q        printk(KERN_ERR "Failed to remap register block\n");
    " w5 u/ [8 r2 p9 Z        return -ENOMEM;; N9 H/ m+ b$ o
        }
    ' W: C6 h6 M6 ?4 o; S0 \( G2 F: F8 c
    9 D5 D) o3 r/ \
        adc_clock = clk_get(NULL, "adc"); //获得ADC的时钟, J2 R' _' s7 G0 B* }/ E* U
        if (!adc_clock)
    6 v5 \2 h4 M. I! j% v1 B    {undefined
    : d6 Z. p, |9 X4 I+ N: p; Q        printk(KERN_ERR "failed to get adc clock source\n");7 X* n$ w, L" r  J% q% C7 \
            return -ENOENT;# H2 L3 j" Y  U+ p) `! \# d) }
        }( {: K5 e+ b2 p, R" o! {6 w
        clk_enable(adc_clock);//使能ADC的时钟/ a" |" c4 H5 O$ n) p
        ! ?* \( u* g" ]! o7 v6 U8 D6 f
        /* normal ADC */- F9 K/ ?0 L1 B4 K
        ADCTSC = 0;//不使用触摸屏2 c6 E$ S2 G! H

    : T$ \4 q. d* h  f9 J0 ?0 f8 \: F
    . B( }* ?/ ?' G$ o5 t
        ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);//注册中断
    / l3 b. E: e( @: ?    if (ret)8 T$ s; q! J  u+ _- H2 K4 S5 \
        {undefined
    , h% i# ^' B# }: J2 d        iounmap(base_addr);
    9 o& Y' _* T( w. w        return ret;
    & ]: W1 D; @2 ]" }# L    }, A) T! N, m: K! W8 e) o) |$ M$ _
    + v8 S+ N0 o2 f& {! k  Y
    ! m8 J- r2 \/ K$ d0 R( M' a6 R
        ret = misc_register(&misc);//注册一个混杂设备
    4 P$ @& D3 V8 N& S( {/ b- a( b, h; G% \9 N0 M4 L: B& B! N% E) V

    % ]$ P$ \. x1 C, U& v2 }    printk(DEVICE_NAME " initialized\n");1 w6 |1 J6 X' \8 m) z
        return ret;" v2 G8 T# `6 @
    }
    8 |. \8 Y; s+ G" p8 J, O0 L0 w
    + y+ U2 F0 m6 j& `3 S0 P
    ) _7 d  P3 G+ I: @: i& d4 E' L
    static void __exit Adc_exit(void)7 l3 y( p# f/ K5 j1 n
    {undefined
    : P% T) |1 O4 P    free_irq(IRQ_ADC, &adcdev);//注销中断
    3 f. v: T$ `/ M/ E$ `    iounmap(base_addr);   //解除映射
    " {3 `9 T3 k8 }- |' ~
    4 w# g0 ?% r/ v
    . P' H! K4 |/ @' O" C
        if (adc_clock)( v9 ]& r# d* ?
        {undefined5 ~1 h- x5 C: A" ^" B/ n( v
            clk_disable(adc_clock);//关闭adc转换的时钟
    * S2 S2 Y' B- |) N( ^* G        clk_put(adc_clock);     
    4 Y( z2 u) U+ X3 h8 Q- P) M+ y1 A6 h        adc_clock = NULL;
    / |3 R2 G9 U' p    }- G5 N3 u- @1 z1 x' y7 \! j% U$ }2 B
    8 Z% x- k8 W. o* i! z( I

    ) E& M! t" |9 j    misc_deregister(&misc);//注销混杂设备, y0 X" \. g; G
    }
    . Y+ Z2 s# P; x! o8 c8 D5 b- u. o1 y* C( m0 e1 C7 \% t

    ( T1 E# }* P! f" y( l1 \EXPORT_SYMBOL(ADC_LOCK);' g- [) |, [- x4 s! g3 K, X
    - `' M5 Q! ^* @/ s" W

    9 f1 w1 ~6 e0 t- I! |: M; s
    # P) \/ h, Q/ k" p

    * y. g+ W. Y, Ymodule_init(Adc_init);
    ; H" O3 q2 J1 U, r/ y) Y$ {/ |module_exit(Adc_exit);# n: a* n. G+ E. a5 |% ^6 b9 l  h. T9 u

    . \1 p2 w- @- D9 C8 w8 H

    ; g6 j$ A7 P) G" D1 V2 E# F5 v
    $ ^9 s" y" M0 L$ r  ?$ U

      S: W" G; ~" q! l3 p, T$ g& RMODULE_LICENSE("GPL");                    & }4 _9 ~0 b1 O2 l6 H) ^
    2、应用程序
    1 I+ C8 ]6 ~1 V3 D, m3 H0 V, U/ ~5 R) S6 S0 x

    0 n% X2 E, J) r' n" [, }  @#include <stdio.h>
    * F& F% G" H) ^: k% o+ ~+ _- ]#include <stdlib.h>& j$ J& E) P( f/ r/ g2 x
    #include <unistd.h>
    $ M% \6 T7 s( h  r* x#include <sys/ioctl.h>! A% O8 o1 U! L
    #include <sys/types.h>  z% d& y/ @5 a) T$ ]
    #include <sys/stat.h>
    ( X( Z" s! o/ y9 g" x' U; u#include <fcntl.h>$ v' u: n% f  J* G. B0 y& E
    #include <sys/select.h>7 A' _% `1 d% m: Y
    #include <sys/time.h>- c" Z' b: s* [0 |, Z
    #include <errno.h>
    ' m+ `1 f8 w$ O8 X* ?#include <linux/input.h>( t3 D/ v2 _+ B
    int main(void)
    * k8 a$ Z) [( V9 T+ f& C) ^{undefined6 W! c9 t4 `2 A
        int adc_fd;; B. q9 N5 i$ L0 s: I- K" d
        int count;, h: q/ h" U8 A$ K, z0 B% B
        char adc[6];. [9 m+ q. l" F5 C& n
        adc_fd = open("/dev/adc", O_RDWR); //以阻塞的方式打开设备文件
    % z9 Z3 v$ W3 v/ Q3 `7 ^, p/ o    if (adc_fd < 0) {undefined
    " ^0 ?/ d' V5 K: u        perror("open device adc_fd");. u4 `; X  X8 a; L3 k3 d
            exit(1);
    - G$ O! M& z$ S! |    }
    - Z# ^) v9 m$ M% y$ u5 p- |, J8 X# [0 I' A

    ) ]9 A! _& M3 J  L4 t4 k4 H4 x8 @    for (;;) {undefined# u. d. h. V1 m6 V) H/ ^  V
            count = read(adc_fd,&adc,sizeof(adc));- z. @3 v( ~! U6 q  ^% f8 r7 u
            adc[count]='\0';
    / X1 w, C! [: w6 w        printf(" adc = %s\n", adc);, X" Q5 @# B5 t: x
                    sleep(2);//2秒钟采样一次5 z% z2 L2 P( R/ x% U( [9 V

    3 o, u( H6 h, x( P- o1 k

    - U% K( W. z2 O- o: b9 g+ H    }
    6 @6 I, F) M* D4 ~% F  y. d9 C2 P2 l$ U% R; S. |

    8 E$ @0 a7 o6 I7 |" d2 ~    close(adc_fd);. O) K9 S) @- K1 j7 A
        return 0;
    " k# F) ?) H' H}& U: V1 _$ a0 |* \& `
    希望能帮到你, {4 I$ G9 L' z* X+ y8 Q. }, Q

    0 J4 ?- k0 s# t% |

    点评

    可是我没有那些宏定义与头文件啊?  详情 回复 发表于 2021-12-23 16:28
  • TA的每日心情
    擦汗
    2021-8-10 15:35
  • 签到天数: 140 天

    [LV.7]常住居民III

    3#
     楼主| 发表于 2021-12-23 16:28 | 只看该作者
    damengshu 发表于 2021-12-23 13:54
    7 Y1 E1 E+ l9 c! {! f1、驱动源代码

    8 f! m( g( S1 z' m( a3 f1 Z6 q可是我没有那些宏定义与头文件啊?! d2 n8 [( B+ n" i
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-9-30 02:42 , Processed in 0.140625 second(s), 24 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表