2017.06.23更新

大家好!

我又重新開始上英文家教了。去年我上了半年,效果很好,但是太忙了,停下來專心念軟體的書籍。

明年有重要任務需要從現在起好好練英文口說。

 

我剛才試了一下,我還是只能用PayPal買點數的方式購買,信用卡試了四張都不能用。

 

因為我的DMM點數還有一些,所以下面我只買了5352日元。

我這次發現買點數可以自選金額,不一定要買5000等整數。

DMM漲價了,去年是4950日元/月,今年是5500日元。

 

 

下面是我成功購買的畫面。

重點是我下次要記得再買DMM點數。真有點麻煩哩。

 

 

 

半年多沒上,daily news的介面也換了。

https://app.eikaiwa.dmm.com/daily-news

 

我覺得這個介面滿不錯的,文章比之前多很多。

 

 

-------------------------------------------------------------------

2016.10.1 新增DMM英會話購買課程教學

前言: 在此教學我買課程的方式,若是DMM封我,我會改到Rarejob上課。

https://www.rarejob.com/

我沒在Rarejob上過課,但是我google過風評不錯,價格比DMM貴一點點而已。

 

以下是教學文

因為我上次試過,我的信用卡被DMM拒絕,我用過兩家信用卡都不行,

只好用Paypal先買點數,我一次買5000點(即5000日元),Paypal最後也會轉成信用卡付費,但是我覺得還是信用卡每月扣款比較方便。

好像也比較便宜。

有網友跟我說他的信用卡不會被擋。若願意公開信用卡銀行的網友請在下面留言。

 

因為我的點數是上次買好的,所以下面沒有寫教學文。總之買DMM點數也是要連日本的Proxy才能順利購買。

 

(1) 登入後,請按下橘色字的"入會xxx" -->抱歉不懂日文,總之是付費的意思。

 

 

(2) 請用日本的proxy (代理伺服器) 

http://www.cybersyndrome.net/search.cgi?q=JP

這裡有列表,功能是要讓你的IP變成從日本發出,才不會被擋。

開了proxy會變很慢,若是太慢導致網頁錯誤,請再換其他proxy,總有比較快的。

 

(3) 步驟(1) 按下後會有課程方案,然後我選擇1天1堂課的那種。(4950日元/月) -->這裡我少抓了一頁圖。

再按下一步就會到下圖。我用DMM點數付,所以選右邊。

 

 

下面的圖是用google的翻譯顯示出來的頁面,你可以看到若你要

 

 

(4) DMM會請你確認課程內容。

 

(5) 付款完成

 

(6) YA!可以快樂的訂課程了

DMM只有擋購買的流程,若已成功購買課程,在選課時不需要用日本Proxy。

 

 

(7) 我習慣都上每日新聞。

http://eikaiwa.dmm.com/dailynews/

這是DMM每日教材的網站。(每日更新)

據我了解,教師們用的介面和我們不同,當然我們是看不到的。

 

(8) 完成預約後,在首頁會有下次課程的時間。

記得日本的時間比台灣快1小時。

 

希望對大家有幫助。

 

--

2016. 9. 9 更新

剛才發現有個方法能買DMM點數。(某種線上支付)

但是因為我在Engoo還有幾堂課,過幾週我再試試能不能用。

點數買到了但是還沒有訂課,若幾週後有訂到再跟大家說。

 

--

2016. 9. 9 更新

上星期我改買Engoo一個月8堂課1399的方案,結果我發現這麼貴的方案竟然不能取消。

(取消視同放棄。)

讓我非常生氣,下次再也不買Engoo課程了。

DMM其實我用VPN就能解決擋IP的問題,但是擋信用卡的問題我還在處理中,有網友跟我說方法,我要試試看。

 

另外還有一個網站我在評估 Rare Job英會話,也是日本的網站,比DMM貴一點,但是比Engoo便宜。

https://www.rarejob.com/

 

---

2016.9.4更新

目前我也被擋了。無法在DMM付款。呃呃..請各位各顯神通試試有沒有其他方法吧。Engoo實在貴太多了。

 

 

---

2016/07/04

後記,我已經轉到DMM上課。因為DMM比較便宜。

Engoo加上DMM已經上了超過半年了,覺得DMM非常的好,很鼓勵想學英文口語的人可以多利用DMM。

DMM的註冊沒有問題,我朋友最近註冊付款都沒有問題。

您可以先試聽兩堂課,喜歡再付錢。

付款的順序是當您選擇買課程後,它會先請您註冊信用卡號,然後再購買課程。

-------------------------------------------------------------------

我是Engoo的會員,
今天無意間發現DMM和Engoo提供相同的服務。
但是DMM便宜很多。
今天花時間試聽,和Engoo的老師雷同度90%,但是介面好用,
教材更加豐富。
真的滿棒的。

DMM英会話 ​​​​​​缺點是純日文介面,時差1小時。但是我覺得OK。
網址 http://eikaiwa.dmm.com/

另外我發現日本的線上英文家教公司非常多,有興趣可以去看看。
這裡有表
http://englishlands.net/online-eikaiwa-creditcard/

mybeauty 發表在 痞客邦 PIXNET 留言(35) 人氣()

 

來源

https://stackoverflow.com/questions/8158007/how-to-jump-the-program-execution-to-a-specific-address-in-c

 

Inline assembly might be the easiest and most "elegant" solution, although doing this is highly unusual, unless you are writing a debugger or some specialized introspective system.

Another option might be to declare a pointer to a void function (void (*foo)(void)), then set the pointer to contain your address, and then invoke it:

void (*foo)(void) = 0x12345678;
foo();

There will be things pushed on the stack since the compiler thinks you are doing a subroutine call, but since you don't care about returning, this might work.

shareimprove this answer

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

Linux Device Driver - IOCTL (copy_to_user & copy_from_user)

 
在 linux/include/linux/fs.h 中定義許多file operation能用的handler
這一次我針對的是 read、ioctl做練習
file operation中沒實做到的handler會被定義成NULL
這一支程式會先得到來自kernel的回應,接著kernel 換更改指定的數字

先大概說一下主要概念
我要先寫一個mydev.c 當作 driver
執行完make 之後 就把 mydev.ko 加入到 kernel中
此時的 mydev.ko 就是模組, 一個在kernel中的模組了
那要如何與此模組互動呢?
我要再寫一個 test_mydev.c 當作 user
直接把他 gcc 產生執行檔 再指定我要跟mydev 模組溝通

首先先來看 ioc.h
這裡定義了 user 能夠透過 ioctl 傳達的指令
IOC_MAGIC 是device 的 major number , 而我定義其major number為 k
每一個裝置都有其major number 與 minor number
接著我設置 SETNUM  GETNUM  XNUM 3種指令
_IOW  _IOR  _IOWR 是 kernel 的巨集 , 我們用這3個巨集來定義我們的命令要做哪些事
各聚集裡的1,2,3 是自訂的minor number

#ifndef IOC_H
#define IOC_H

#define IOC_MAGIC 'k'
#define SETNUM _IOW(IOC_MAGIC, 1 , int)
#define GETNUM _IOR(IOC_MAGIC, 2 , int)
#define XNUM _IOWR(IOC_MAGIC,3 , int)
#define IOC_MAXNR 3

#endif



接著看到最主要的 driver code : mydev.c
在file operations 中定義了我自訂的操作函數
dev_open : 在user open  device file 時會被呼叫
dev_close : 在user close device file 時會被呼叫
dev_ioctl  :  switch case 中寫了各種command該執行的動作
         若user 呼叫 ioctl 時傳入 SETNUM 則 driver 會將傳入的資料(args)取出,並指定給val 變數
         若user 呼叫 ioctl 時傳入 GETNUM 則 driver 會將val 變數傳出(args)
         若user 呼叫 ioctl 時傳入XNUM 則 driver 會將 user 輸入的數值指派給val變數達到更改資料
         的目的
         (因為user space 與 kernel space 儲存data的空間不同, 因此要用 copy_to_user 與
         copy_from_user來轉遞資料)
dev_read : user 呼叫 read時會被呼叫, 我在這裡放了一個hello字串, kernel會利用copy_to_user 傳到
                 buffer中給user
dev_write: 我在這裡沒用到
init_modules:  程式進入點 , 建立裝置並註冊到kernel
exit_modules: 程式結束 , 移除裝置

#include <linux/init.h>
#include <linux/module.h>

#include <linux/fs.h> //chrdev
#include <linux/cdev.h> //cdev_add() / cdev_del()

#include <asm/uaccess.h> //copy_*_user()

#include "ioc.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("IRENE 2013/09/01");
#define DEV_BUFSIZE 1024

static int dev_major;
static int dev_minor;
struct cdev *dev_cdevp = NULL;
static int dev_open(struct inode*, struct file*);
static int dev_release(struct inode*, struct file*);
static int dev_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
ssize_t dev_read(struct file*, char __user*, size_t, loff_t*);
ssize_t dev_write(struct file*, char __user*, size_t, loff_t*);
static void __exit exit_modules(void);

//Functions on the right side are the handler we just defined
struct file_operations dev_fops = {
   .owner = THIS_MODULE,
   .open = dev_open,
   .release= dev_release,
   .ioctl = dev_ioctl,
   .read = dev_read,
   .write = dev_write
};


// dev_open will be Called when user open the device file
static int dev_open(struct inode *inode, struct file *filp)
{
       printk("%s():\n",__FUNCTION__);
       return 0;
}

// dev_release will be Called when user close the device file
static int dev_release(struct inode *inode, struct file *filp)
{
       printk("%s():\n",__FUNCTION__);
       return 0;
}

// mainly io control between user and kernel
// args are pointed to user space's buffer
static int val = 0;
static int dev_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long args)
{
      int tmp, err=0,ret=0;

      if(_IOC_TYPE(cmd) != IOC_MAGIC)
              return -ENOTTY;
      if(_IOC_NR(cmd) > IOC_MAXNR)
              return -ENOTTY;
      if(_IOC_DIR(cmd) & _IOC_READ){
              err = !access_ok(VERIFY_WRITE, (void __user*)args, _IOC_SIZE(cmd));
      } else if (_IOC_DIR(cmd) & (_IOC_WRITE)){
              err = !access_ok(VERIFY_READ, (void __user *)args,_IOC_SIZE(cmd));
      }

      if (err)
              return -EFAULT;

      switch (cmd) {
        case SETNUM:
             //copy data from args(user) to val(kernel)
             if(copy_from_user(&val,(int __user *)args,1))
                 return -1;

             printk("%s():get val from user = %d\n",__FUNCTION__,val);
                   break;
        case GETNUM:
                        //copy data from val to args
              if(copy_to_user((int __user *)args,&val,1))
                    return -1;

              printk("%s():set val to %d\n",__FUNCTION__, val);
                    break;
        case XNUM:
                       // exchange data passed by user
              tmp = val;
              if(copy_from_user(&val,(int __user *)args,1))
                        return -1;

              if(copy_to_user((int __user *)args,&val,1))
                        return -1;

           printk("%s():change val from %d to %d\n",__FUNCTION__,tmp,val);
           break;

        default: /* redundant. as cmd was checked against MAXNR */
                 return -ENOTTY;
     }
     return 0;
}


static const char str[]="Hello Irene from kernel!";
static const ssize_t str_size = sizeof(str);
// send messages to user
ssize_t dev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{

     printk("%s():\n",__FUNCTION__);

     if( *f_pos >= str_size)
          return 0;
     if( *f_pos + count > str_size)
        count = str_size - *f_pos;
     if (copy_to_user(buf, str + *f_pos, count))
        return -EFAULT;
     *f_pos += count;
     return count;

}

ssize_t dev_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
     printk("%s():\n",__FUNCTION__);
     return 0;
}

static int __init init_modules(void)

   dev_t dev;
   int ret;
   // get major number dynamically
   ret = alloc_chrdev_region(&dev, 0, 1, "mydev");
   if (ret <0){
      printk("can't alloc chrdev\n");
      return ret;
   }
   dev_major = MAJOR(dev);
   dev_minor = MINOR(dev);
   printk("register chrdev(%d,%d)\n",dev_major,dev_minor);

   dev_cdevp = kmalloc(sizeof(struct cdev), GFP_KERNEL);
   if (dev_cdevp == NULL){
        printk("kmalloc failed\n");
        goto failed;
   }
   // system call handler
   cdev_init(dev_cdevp, &dev_fops);
   dev_cdevp->owner = THIS_MODULE;
   //register my device to kernel
   ret = cdev_add(dev_cdevp, MKDEV(dev_major, dev_minor),1);
   if(ret < 0){
        printk("add chr dev failed\n");
        goto failed;
   }
   return 0;

failed:
   if(dev_cdevp) {
   kfree(dev_cdevp);
   dev_cdevp = NULL;
}
  return 0;
}


static void __exit exit_modules(void)
{
   dev_t dev;
   dev = MKDEV(dev_major, dev_minor);
   if (dev_cdevp){
      cdev_del(dev_cdevp);
      kfree(dev_cdevp);
    }
   unregister_chrdev_region(dev,1);
   printk("unregister chrdev\n");
}

module_init(init_modules);
module_exit(exit_modules);



接著 是 user 端部分啦 test_mydev.c
執行時要輸入的參數有 devicefile num
device file 就是 在 /dev下的裝置檔名
num 是 XNUM命令時要change的value (default 是 10 )
首先利用 open 打開 device file
然後 read(fd, buffer, sizeof(buffer));
buffer 是 user 拿來放kernel 回傳值的地方
此時kernel 會回傳 Hello Irene from kernel!
接著 user 開始下達 ioctl command
--> ioctl(fd, SETNUM, &ret)
這是其中一個例子 , SETNUM 便是user 下達的command
而&ret 是 回傳值的指標

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ioc.h"

int main(int argc, char *argv[])
{
       int fd, ret=10;
       unsigned char buffer[50]={};
       if(argc < 2)
       { 
         printf("Usage: /dev/mydev param1.. \n"); 
         return -1;
       }
       // open dev file
       fd=open(argv[1], O_RDWR);
       if(fd < 0)
       {
           printf("open %s failed\n", argv[1]);
           return -1;
       }
       //read from kernel  
       read(fd, buffer, sizeof(buffer));
       printf("%s\n",buffer);
       // set num to 10
       if (ioctl(fd, SETNUM, &ret)< 0)
       {
           printf("set num failed\n");
           return -1;
       }
       if(ioctl(fd, GETNUM , &ret)< 0)
       {
           printf("get num failed\n");
       }
       printf("get default value=%d\n",ret);
       // exchange number ret =atoi(argv[2]);  
       if (ioctl(fd, XNUM, &ret)<0)
       {
           printf("exchange num failed\n");
           return -1;
        }
       printf("get value = %d\n",ret);
       return 0;
} 


最後是 Makefile








上面全部的檔案都存在mydev 資料夾中
/usr/src/kernels/linux-2.6.18/mydev/..

開始執行
make 之後的指令如下
 











在 insmod之後 dev會被賦予 major number 與 minor number 
開啟新的cmd 執行dmesg就可以看到kernel傳來一條msg
register  chrdev(252,0)
或是可以到 /proc/devices中查看 major number 與 minor number
在mknod時一定要給定對的major 與 minor number
否則會有 找不到 file 的錯誤
執行後可以看到
kernel 傳回一條 hello messages
而kernel也將預設為10 的value改為 user 設定的 100
最後dmesg中可以看到kernel的訊息

 










研究好多天仍有很多疑問, 有不完備之處之後繼續修改
參考:
 http://csw17.pixnet.net/blog/post/11506143
http://nano-chicken.blogspot.tw/2009/12/linux-modulesv-ioctl.html
http://www.codeproject.com/Articles/112474/A-Simple-Driver-for-Linux-OS
強烈建議大家在寫這個之前先到jollen的網站看相關的 device 觀念教學

 

 

 

 

 

文章來源

http://blackcat12573.blogspot.tw/2013/09/linux-device-driver-ioctl-copytouser.html

mybeauty 發表在 痞客邦 PIXNET 留言(1) 人氣()

來源:

Linux 驅動程式的 I/O, #3: kernel-space 與 user-space 的「I/O」

Linux 驅動程式的 I/O, #4: fops->ioctl 實作

 

重要觀念

任何作業系統底下的「驅動程式」,都需要分二個層面來討論所謂的「I/O 處理」:

1. 實體層:驅動程式 v.s. 硬體。

2. 虛擬層:驅動程式 v.s. user process

在前一篇日記「Linux 驅動程式的 I/O, #2: I/O 存取相關函數」中所提到的 I/O 函數是處理「實體層」的 I/O;本日記所要介紹的 copy_to_user()  copy_from_user() 則是在處理「虛擬層」的 I/O。另外,在繼續往下讀之前,您必須了解以下的觀念都是「等價」的:

1. 驅動程式與 user process 的 I/O;等於

2. 驅動程式與 user process 間的 data communication;等於

3. kernel-space 與 user-space 間的 data communication。

此外,還要了解:

1. user-space 無法「直接」存取 kernel-space 的記憶體。

2. 「Linux device driver」與「user-space」間的 I/O 會與 fops->readfops->write  fops->ioctl 共三個 system call 有關。

copy_to_user() 與 copy_from_user()

了解以上的觀念後,再來「直接殺進重點」就很容易懂了:從 user-space 讀取資料至 kernel-space,或是將 kernel-space 的資料寫至 user-space,「必須」透過 kernel 提供的 2 個 API 來進行。這二個 API 如下:

˙ long copy_to_user(void *to, const void *from, long n);
˙ long copy_from_user(void *to, const void *from, long n);

參數說明,以 copy_to_user() 來說:

˙ to:資料的目的位址,此參數為一個指向 user-space 記憶體的指標。
˙ from:資料的來源位址,此參數為一個指向 kernel-space 記憶體的指標。
˙ 口訣:copy data to user-space from kernel-space

 copy_from_user() 來說:

˙ to:資料的目的位址,此參數為一個指向 kernel-space 記憶體的指標。
˙ from:資料的來源位址,此參數為一個指向 user-space 記憶體的指標。
˙ 口訣:copy data from user-space to kernel-space

由 user-space 讀取資料,或是寫入資料給 user-space 的 3 個 driver method 為:read、write與ioctl。

另外,指向 user-space 的指標是 kernel 回呼 driver method 時所傳遞進來的,可由 read、write 與 ioctl driver function 的函數原型宣告來觀察(紅色部份):

˙ int card_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
˙ ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp);
˙ ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);

fops->ioctl 的參數 arg、fops->write 與 fops->read 的參數 buff 是指向 user-space 資料的指標。撰寫程式時,要注意資料型別上的不同。

 

 

基本觀念

需要由 user-space 讀取資料,或是寫入資料給 user-space 的主要 3 個 driver method 為:read、write 與 ioctl。指向 user-space 資料空間(buffer)的指標是 kernel 回呼 driver method 時所傳遞進來的,我們由 read、write 與 ioctl 的函數原型宣告來說明如何撰寫程式:

˙int card_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
˙ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp);
˙ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);

fops->ioctl 的參數 argfops->write  fops->read 的參數 buff 是指向 user-space 資料的指標。撰寫程式時,要注意資料型別上的不同。

實作 fops->ioctl

ioctl 代表 input/output control 的意思,故名思義,ioctl system call 是用來控制 I/O 讀寫用的,並且是支援user application存取裝置的重要 system call。因此,在 Linux 驅動程式設計上,我們會實作 ioctl system call 以提供 user application 讀寫(input/output)裝置的功能。

依此觀念,當 user application 需要將數字顯示到 debug card 時。範例 debug card 0.1.0 便需要實作 ioctl system call,然後在 fops->ioctl 裡呼叫 outb() 將 user application 所指定的數字輸出至 I/O port 80H。

User application 使用 GNU LIBC 的 ioctl() 函數呼叫 device driver 所提供的命令來「控制」裝置,因此驅動程式必須實作 fops->ioctl以提供「命令」給使用者。

fops->ioctl 函數原型如下:

int ioctl(struct inode *, struct file *, unsigned int, unsigned long);

Linux 驅動程式以一個唯一且不重覆的數字來代表 ioctl 的命令,設計 Linux 驅動程式時,我們必須使用 kernel 所提供的巨集來宣告命令。根據命令的「方向」,kernel 提供以下 4 個巨集供我們宣告 ioctl 命令:,

  • _IO(type,nr):表示此 ioctl 命令不指定資料向方
  • _IOR(type,nr,dataitem):此 ioctl 命令由裝置 (driver) 讀取資料
  • _IOW(type,nr,dataitem):此 ioctl 命令將資料寫入裝置
  • _IOWR(type,nr,dataitem):此 ioctl 命令同時讀寫資料

若 user application 呼叫到驅動程式未提供的命令,則回傳 -ENOTTY 錯誤代碼。

debug card 0.1.0 範例裡,我們宣告了一個 IOCTL_WRITE 命令,當 user application 呼叫此命令後,驅動程式會將 user application 所指定的數字顯示在 debug card 上。由於我們的資料方向為「寫入裝置」,因此使用的宣告巨集為 _IOW

Debug card 0.1.0 實作 fops->ioctl 的完整程式片斷如下:

#include <linux/ioctl.h>

#define	DEV_MAJOR	121
#define	DEV_NAME	"debug"
#define  	DEV_IOCTLID	0xD0
#define	IOCTL_WRITE	_IOW(DEV_IOCTLID, 10, int)

unsigned long IOPort = 0x80;

void write_card(unsigned int);

void write_card(unsigned int num)
{
	outb((unsigned char)num, IOPort);
}

int card_ioctl(struct inode *inode, struct file *filp,
	  unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
		case IOCTL_WRITE:
			write_card((unsigned int)arg);
			break;
		default:
			return -1;
	}
    	return 0;
}

struct file_operation 的定義並未列出,不過請別忘了在 fops 裡加上 ioctl system call 的欄位。

User-space

以 debug card 0.1.0 驅動程式為例,user-space 的測試程式寫法如下:

int main(int argc, char *argv[])
{
    int devfd;
    int num = 0;

    if (argc > 1) num = atoi(argv[1]);
    if (num < 0) num = 0xff;

    devfd = open("/dev/debug", O_RDONLY);
    if (devfd == -1) {
	printf("Can't open /dev/debug\n");
	return -1;
    }

    printf("Write 0x%02x...\n", num);
    ioctl(devfd, IOCTL_WRITE, num);
    printf("Done. Wait 5 seconds...\n");
    sleep(5);
    close(devfd);

    return 0;
}

 

來源

http://huenlil.pixnet.net/blog/post/23507650

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

動手寫 Linux Driver

 
先前為了一個期末專題花了一點時間研究怎麼在 Linux 作業系統上寫一個 PCI Driver。寫過 Linux 驅動程式之後,覺得 Linux 的架構真的很漂亮!為了怕以後忘記怎麼寫,所以就把他寫下來記錄成一篇文章。
 

建構編譯環境


先我們必須要準備開發 Linux 驅動程式所需的環境,在 Debian 上可以用以下的指令達到這個目的:

$ sudo apt-get install build-essential linux-headers-$(uname -r)

其中 build-essential 會安裝 gcc, make 等軟體開發必要的工具,而 linux-headers 會安裝開發 Linux 驅動程式必要的 SDK。因為 linux-headers 會隨核心的版本而有所不同,所以我們要使用 $(uname -r) 取得目前核心的版本。
 

簡單的驅動程式


所有的 Linux 驅動程式至少要包含一個 MODULE_LICENSE 用以宣告驅動程式的授權,另外還需要一個 init 與一個 exit 函式,分別處理驅動程式的起始與終止。以下就是一個什麼都沒有的空殼:

/* example.c */
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("Dual BSD/GPL");

static int example_init(void) {
    printk("<1>EXAMPLE: init\n");
    return 0;
}

static void example_exit(void) {
    printk("<1>EXAMPLE: exit\n");
}

module_init(example_init);
module_exit(example_exit);

我們可以注意到裡面有一個 printk,他就相當於驅動程式設計當中的 printf。我們如果需要印任何除錯資訊,可以呼叫 printk,然後使用 sudo dmesg 觀看結果。編譯這個檔案之前,我們要先幫他寫 Makefile:

obj-m := example.o

ifeq ($(KERNELDIR),)
KERNELDIR=/lib/modules/$(shell uname -r)/build
endif

all:
    make -C $(KERNELDIR) M=$(PWD) modules

clean:
    make -C $(KERNELDIR) M=$(PWD) clean

在這個 Makefile 裡面,我們會使用 obj-m 這個變數指定我們要編譯的模組,然後再呼叫 make 讓他載入 SDK 的 Makefile。我們先前安裝的 SDK 就會放在 /lib/modules/$(shell uname -r)/build 裡面。

接下來我們就可以用 make 編譯我們的模組,並使用以下指令載入、卸除模組:

$ sudo insmod ./example.ko
$ sudo rmmod example

如果要看我們的模組有沒有輸出任何訊息,可以使用:

$ sudo dmesg | tail
 

註冊為 Character Device


在 Unix 的設計哲學當中,所有的東西都是檔案,硬體也不例外。我們寫驅動程式的時候要提供一個檔案操作的介面給 Userspace 的程式。為了達到這個目的,我們必須再引入一個標頭檔:

#include <linux/fs.h>

然後定義若干檔案操作與 file_operations 這個資料結構:

static int example_open(struct inode *inode, struct file *filp) {
    printk("<1>EXAMPLE: open\n");
    return 0;
}

static int example_close(struct inode *inode, struct file *filp) {
    printk("<1>EXAMPLE: close\n");
    return 0;
}

static ssize_t example_read(struct file *filp, char *buf, size_t size, loff_t *f_pos) {
    printk("<1>EXAMPLE: read  (size=%zu)\n", size);
    return 0;
}

static ssize_t example_write(struct file *filp, const char *buf, size_t size, loff_t *f_pos) {
    printk("<1>EXAMPLE: write  (size=%zu)\n", size);
    return size;
}

static struct file_operations example_fops = {
    .open = example_open,
    .release = example_close,
    .read = example_read,
    .write = example_write,
};

然後在 example_init() 當中用 register_chrdev 把這個驅動程式註冊為一個 Character Device。

#define EXAMPLE_MAJOR 60
#define EXAMPLE_NAME "example"

static int example_init(void) {
    int result;
    printk("<1>EXAMPLE: init\n");

    /* Register character device */
    result = register_chrdev(EXAMPLE_MAJOR, EXAMPLE_NAME, &example_fops);
    if (result < 0) {
        printk("<1>EXAMPLE: Failed to register character device\n");
        return result;
    }

    return 0;
}

值得一提的是第一個參數 EXAMPLE_MAJOR 可以是 60, 61, 62。如果是正式要釋出的 Driver,就必須要從 Documentation/devices.txt 選取適當的 Major ID。當然,在 example_exit() 我們也必需加上對應的 unregister:

static void example_exit(void) {
    printk("<1>EXAMPLE: exit\n");

    /* Unregister character device */
    unregister_chrdev(EXAMPLE_MAJOR, EXAMPLE_NAME);
}

在重新編譯之後,我們可以用 insmod 載入驅動程式,然後使用 mknod 建立 Device File。然後我們就可以在 User Space 使用一般的檔案讀寫操作這個 Device。

$ sudo insmod ./example.ko

$ sudo mknod /dev/example c 60 0
# /dev/example 是我們要存放檔案的路徑,c 代表 Character Device,60 是這個驅動程式的 Major ID,0 是驅動程式的 Minor ID。

$ sudo chmod 666 /dev/example
# 為了方便測試,我們把這個 Device 改成所有人都可以讀寫。

$ echo -n 'abcd' > /dev/example

$ sudo dmesg | tail
 

讀取 User Space 的資料


在前一節當中我們提供了一個 API 讓 User Space 可以操作 Driver。但是其實我們是不能直接存取 buf 的內容。因為 Kernel Space 與 User Space 有不同的位址空間,所以不能直接存取他們。我們必須借助 copy_from_user 這個 API。

在使用這個 API 之前,我們必需引入 <asm/uaccess.h>:

#include <asm/uaccess.h>

然後我們就可以使用 copy_from_user 來存取 User Space 的位址空間,舉例來說:

ssize_t example_write(struct file *filp, const char *buf, size_t size, loff_t *f_pos) {
    size_t pos;
    uint8_t byte;
    printk("<1>EXAMPLE: write  (size=%zu)\n", size);
    for (pos = 0; pos < size; ++pos) {
        if (copy_from_user(&byte, buf + pos, 1) != 0) {
            break;
        }
        printk("<1>EXAMPLE: write  (buf[%zu] = %02x)\n", pos, (unsigned)byte);
    }
    return pos;
}

值得注意的是 copy_from_user() 會回傳剩下未完成的 byte 數。所以一般來說這個回傳值必須是 0 才是成功地讀入資料。要把資料從 Kernel Space 複製到 User Space 則是使用 copy_to_user() 函式,至於使用方法就不再贅述。

$ echo -n 'abcd' > /dev/example
$ sudo dmesg | tail 
 

小結


透過這個小練習,我們可以知道要怎麼開始寫一個 Linux Driver。在下一結我們會從 QEMU 的角度出發,建立一個 QEMU 的虛擬裝置,讓 QEMU Guest OS 的驅動程式可以和外面的 QEMU 虛擬裝置相互溝通。
 

參考資料

 

 

來源

http://blog.logan.tw/2013/01/linux-driver.html

 

 

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

 

LibCurl supports URL transfer over HTTPS protocol. In this post we’ll use LibCurl to download a webpage over HTTPSprotocol. To get started, make sure that you have setup your system as outlined in one of my previous posts. Note that LibCurl comes with SSL libraries included and hence you need not to install any extra packages.

Getting started

Let’s first try to download a HTTPS webpage without SSL using following code:

 1 #include <stdio.h>
 2 #define CURL_STATICLIB
 3 #include <curl/curl.h>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     CURL *curl;
 8     CURLcode res;
 9 
10     curl = curl_easy_init();
11     if (curl)
12     {
13         curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
14         /* google.com is redirected, so we tell LibCurl to follow redirection */
15         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
16 
17         /* Perform the request, res will get the return code */
18         res = curl_easy_perform(curl);
19         /* Check for errors */
20         if(res != CURLE_OK)
21             fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
22 
23         /* Always cleanup */
24         curl_easy_cleanup(curl);
25     }
26 
27     return 0;
28 }

When we compile and run the above program, we get following error:

curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates

Well we can force LibCurl not to verify the authencity of peer’s certificate by modifying the program as below:

 1 #include <stdio.h>
 2 #define CURL_STATICLIB
 3 #include <curl/curl.h>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     CURL *curl;
 8     CURLcode res;
 9 
10     curl = curl_easy_init();
11     if (curl)
12     {
13         curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
14         /* google.com is redirected, so we tell LibCurl to follow redirection */
15         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
16         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
17         /* Perform the request, res will get the return code */
18         res = curl_easy_perform(curl);
19         /* Check for errors */
20         if(res != CURLE_OK)
21             fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
22 
23         /* Always cleanup */
24         curl_easy_cleanup(curl);
25     }
26 
27     return 0;
28 }

This will resolve the error we were getting earlier but this is not secure as we are bypassing the verification of SSLcertificte presented by peer.

LibCurl with SSL

Now let’s modify the code as below to enable SSL certificate verification by LibCurl:

 1 #include <stdio.h>
 2 #define CURL_STATICLIB
 3 #include <curl/curl.h>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     CURL *curl;
 8     CURLcode res;
 9 
10     curl = curl_easy_init();
11     if (curl)
12     {
13         curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
14         /* google.com is redirected, so we tell LibCurl to follow redirection */
15         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
16         /* SSL Options */
17         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
18         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
19         /* Provide CA Certs from http://curl.haxx.se/docs/caextract.html */
20         curl_easy_setopt(curl, CURLOPT_CAINFO, "ca-bundle.crt");
21 
22         /* Perform the request, res will get the return code */
23         res = curl_easy_perform(curl);
24         /* Check for errors */
25         if(res != CURLE_OK)
26             fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
27 
28         /* Always cleanup */
29         curl_easy_cleanup(curl);
30     }
31 
32     return 0;
33 }

LibCurl depends on ca-bundle.crt to verify server’s certificate. CA bundle extract is provided by LibCurl itself and you can download it from here. We need to place the ca-bundle.crt in same folder as our executable. Also notice that we have enabled CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST in lines 17 and 18. When CURLOPT_SSL_VERIFYPEER is enabled, LibCurl verifes if the ceriticate presented is authentiate or not. If the verification fails to prove that the certificate is authentic, the connection fails. Authenticating the certificate is not enough to be sure about the server. We also want to ensure that the server is the server we mean to be talking to. When CURLOPT_SSL_VERIFYHOST is enabled, LibCurl checks that the host name in the certificate is valid for the host name we’re connecting to. If LibCurl fails to verify this, the connection fails.

 

 

 

 

 

來源

https://pranavprakash.net/2014/09/27/using-libcurl-with-ssl/

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

最近在做使用openssl链接http和https的项目,编译时出现以下问题。

/usr/local/openssl/lib/libcrypto.a(async.o): In function `async_free_pool_internal':
async.c:(.text+0xe4): undefined reference to `pthread_setspecific'
async.c:(.text+0xf4): undefined reference to `pthread_getspecific'
async.c:(.text+0x104): undefined reference to `pthread_setspecific'
/usr/local/openssl/lib/libcrypto.a(async.o): In function `ASYNC_init_thread.part.1':
async.c:(.text+0x253): undefined reference to `pthread_setspecific'
/usr/local/openssl/lib/libcrypto.a(async.o): In function `async_start_func':
async.c:(.text+0x36f): undefined reference to `pthread_getspecific'
async.c:(.text+0x39e): undefined reference to `pthread_getspecific'
/usr/local/openssl/lib/libcrypto.a(async.o): In function `ASYNC_start_job':
async.c:(.text+0x404): undefined reference to `pthread_getspecific'
async.c:(.text+0x41e): undefined reference to `pthread_getspecific'
async.c:(.text+0x433): undefined reference to `pthread_getspecific'
/usr/local/openssl/lib/libcrypto.a(async.o):async.c:(.text+0x44c): more undefined references to `pthread_getspecific' follow
/usr/local/openssl/lib/libcrypto.a(async.o): In function `ASYNC_start_job':
async.c:(.text+0x7ef): undefined reference to `pthread_setspecific'
async.c:(.text+0x811): undefined reference to `pthread_getspecific'
async.c:(.text+0x82d): undefined reference to `pthread_getspecific'
async.c:(.text+0x83f): undefined reference to `pthread_getspecific'
async.c:(.text+0x870): undefined reference to `pthread_getspecific'
async.c:(.text+0x891): undefined reference to `pthread_getspecific'
/usr/local/openssl/lib/libcrypto.a(async.o):async.c:(.text+0x8a6): more undefined references to `pthread_getspecific' follow
/usr/local/openssl/lib/libcrypto.a(async_posix.o): In function `async_global_init':
async_posix.c:(.text+0xc): undefined reference to `pthread_key_create'
async_posix.c:(.text+0x1e): undefined reference to `pthread_key_create'
/usr/local/openssl/lib/libcrypto.a(async_posix.o): In function `async_local_init':
async_posix.c:(.text+0x3d): undefined reference to `pthread_setspecific'
async_posix.c:(.text+0x50): undefined reference to `pthread_setspecific'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':
dso_dlfcn.c:(.text+0x21): undefined reference to `dlopen'
dso_dlfcn.c:(.text+0x34): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x3f): undefined reference to `dlclose'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_bind_func':
dso_dlfcn.c:(.text+0x354): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x3fb): undefined reference to `dlerror'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_bind_var':
dso_dlfcn.c:(.text+0x474): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x52e): undefined reference to `dlerror'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_load':
dso_dlfcn.c:(.text+0x5a4): undefined reference to `dlopen'
dso_dlfcn.c:(.text+0x60b): undefined reference to `dlclose'
dso_dlfcn.c:(.text+0x638): undefined reference to `dlerror'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_pathbyaddr':
dso_dlfcn.c:(.text+0x6ce): undefined reference to `dladdr'
dso_dlfcn.c:(.text+0x731): undefined reference to `dlerror'
/usr/local/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_unload':
dso_dlfcn.c:(.text+0x78a): undefined reference to `dlclose'

 

解决方案:

=======================================================================================================

gcc obj/Debug/main.o -L/usr/local/openssl/lib -lssl -lcrypto -ldl -lpthread -o main

原因分析:

在链接这个库的时候一定要注意2个问题:

1.openssl库的版本问题,请直接链到你需要的openssl库路径,比如我的就是/usr/local/openssl/lib,

2.注意-lssl -lcrypto要写在-ldl -lpthread前面,这四个必须要。

相关知识:

-L :此选项是指定链接库的文件夹地址

-l(小写的L):-lssl 即是寻找/usr/local/openssl/lib目录下的 libssl.a 这个库,编译器会自动寻找 libssl.a或者libssl.so

-I(大写的i):指定头文件的文件夹地址

 
來源
http://www.cnblogs.com/Boyona/p/4999339.html

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

整理virtualBox的上網設定

-------------------------------------------------------------------

 

寫在前面

(1) 這一篇文章是說明VirtualBox內的Ubuntu,設定2張網卡,一張NAT可以透過Host的win 7筆電上大網。

另一張Bridge連到embedded開發板。這是不上大網的,是設定成固定IP

(2) 要注意的事Bridge在VirtualBox裡設定完成之後,要進Ubuntu設定Bridge這張網卡的IP

 

-------------------------------------------------------------------

這一篇是我看過最詳細的說明

VirtualBox能設定4張網卡,連線模式在下面這篇文章寫的很清楚。

http://kanchengzxdfgcv.blogspot.tw/2015/10/oracle-vm-virtualbox.html

 

以下使得Ubuntu可以出大網,也可以和arm的板子對接。

-------------------------------------------------------------------
注意!
/etc/network/interfaces的設定要這樣子寫
NAT那一張不用寫上來
bridge那一張不要設gateway

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

auto enp0s3
iface enp0s3 inet static
address 192.168.0.105
netmask 255.255.255.0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

來源

http://wdpsestea.blogspot.tw/2016/02/inkscape091.html

 

 

inkscape0.91當機問題解決方法

 
這個問題困援許久,本以為我們解決不了,想不到師父就是師父,子忠老師查出哪裡出問題,並把它修復並且釋出檔案。
原來是中文化檔案出問題,並釋出檔案了。請下載此檔案
https://drive.google.com/file/d/0B8MclADHBn8eNlYtZ3BkdEZKT1U/view?usp=sharing

把它放入/usr/share/locale/zh_TW/LC_MESSAGES資料夾中。inkscape0.91版當掉問題就解決了。

 

 

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()

以下為轉貼

http://www.camdemy.com/media/9354/

 

1.
0 ~ 99
10 ~ 12    zero, one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve
13 ~ 19    thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen
20, 30, 40 ... twenty, thirty, forty, fifty, sixty, seventy, eighty, ninety
21, 22, 23 ... twenty-one, twenty-two, twenty-three, ...
2.
百 (hundred)
分成百位、十位及個位
例: 245   two hundred and forty-five   * 中間要加上 and 連接
3.
千 (thousand)
分成千位、百位、十位及個位
例: 2186   two thousand, one hundred and eighty-six   * 逗號 + and 就和 A, B and C 的觀念一樣
4.
萬以上的數
英文數字的分法是三個數三個數一組近位,每組一起念,在千位、百萬位、十億位分別由三個逗號區隔。
第一個逗號是千位,叫做 thousand
第二個逗號是百萬,叫做 million
第三個逗號是十億,叫做 billion
例: 23,569,741,168   twenty-three billion, five hundred and sixty-nine million, seven hundred and forty-one thousandone hundred and sixty-eight
5.
and 觀念與範例
and 的擺放位置是有連續三個或以上的東西,最後要用 and 來連接最後一個東西。
像是 apples, bananas, oranges, and grapes 的觀念一樣。
例: 2,039,100   two million, thirty-nine thousand, and one hundred
     2,233,100   two million, two hundred and thirty-three, and one hundred   * 中間的 and 是三個三個一組的念法    15,500,000   fifteen million and five hundred thousand

mybeauty 發表在 痞客邦 PIXNET 留言(0) 人氣()